# Agents

> How kin's agent system works — isolated task delegation, full-context forkagent delegation, and the --agent <name CLI for running the main session as a profile.

How kin's agent system works — isolated `task` delegation, full-context
`fork_agent` delegation, and the `--agent <name>` CLI for running the main
session as a profile.

<!-- SOURCE: src/kin/harness/tools/task.py, src/kin/harness/tools/fork_agent.py, src/kin/harness/tools/agent_bg.py, src/kin/harness/session/, src/kin/harness/subagents.py, src/kin/harness/agents.py, src/kin/tui/cli.py, src/kin/tui/bg_agents_bar.py, src/kin/tui/agent_panel.py, src/kin/tui/widgets/ -->

## Two delegation contexts

`task` is the fresh-context specialist: its prompt must be self-contained, and
it can choose a named profile or model override. `fork_agent` is the continuity
path: it inherits the represented conversation through the current user
request and keeps the parent's identity and model. Use a fork when prior
discussion changes what “correct” means; use a task for an independent view,
specialist scope, or lower prompt cost.

Both can run foreground or background and become rows in the same supervised
registry. The ambient strip, panel, `agent_list`, and `agent_inspect` state the
scope rather than leaving it implicit.

## Two ways to run a profile

A **profile** is a named toolset + persona (a markdown file with frontmatter; see [Subagents](/docs/kin/guide/subagents/#agent-profiles)). You can run a profile in two ways:

| Path | What it is |
|---|---|
| `task(subagent_type=<name>, prompt=…)` | A **delegation** — the main session stays the main thread; the subagent gets a fresh context with only the `prompt`, runs to completion, and returns a summary. Foreground by default. |
| `kin --agent <name>` | A **launch** — the profile IS the main thread. No parent turn; the CLI walks the same `Session` factory with the profile's tools + system prompt. |

`task` is for fan-out (parallel focused work, isolating a noisy subtask). `--agent` is for running kin as a narrow specialist (a code reviewer, a research analyst) where you do not want the main session's tools or identity.

The two paths share the profile loader (`subagents.resolve_for(workdir)`), the system-prompt composition, and the tool scoping — they cannot drift apart silently.

## Foreground subagents

Foreground is the default `task` path. See [Subagents](/docs/kin/guide/subagents/) for the full surface — profiles, scope, recursion caps, the 32&nbsp;KB result cap. The short version:

- The subagent sees only the `prompt`, never the parent conversation.
- The subagent inherits the parent's permission mode (destructive calls inside it still prompt).
- The subagent's tool calls **fold into the parent's `task` row** (routed via `parent_tool_call_id`): the row's title tracks the latest call live plus a running call counter, and expanding the row shows the full per-call activity log — no separate transcript line per child call. A nested subagent's calls fold into the same line.
- Depth 4 and parallel 3 by default; selected MiniMax/Z.ai subscription tiers
  raise ordinary foreground and background capacity to 4–7 while preserving
  the depth guard.
- **A live-updating timer row.** The moment the spawn actually happens, the tool-call row in the transcript flips to a ⬡ glyph with a ticking elapsed timer (`Ns`) in place of the plain running glyph — so you can see the subagent is working even if it never calls a tool (a self-contained plan review, for instance, might just think and reply). This covers `task`'s foreground path — including when the model dispatches the `critic` subagent itself after you choose **Review plan first (adversarial)** in `present_plan`'s approval modal. The subagent's own prose is still never streamed to the transcript (see [the critic agent](#the-critic-agent) below) — only the timer, the folded activity, and, on finish, the call count + elapsed duration are visible until the result lands.
- **Registered in the agent registry (shared id space with background).** A foreground child gets a stable id (`agent1`, `agent2`, …) and a registry row in `sess.agents`, so `agent_list` / `agent_output` / `agent_kill` reach it mid-run and after it finishes. A running foreground child is killable without cancelling the parent turn — `agent_kill <fg-id>` (or the panel's `x`) cancels the child and the `task` tool returns `error: subagent <id> was killed before finishing`, leaving the parent turn free to continue. ++escape++ on the parent turn still cancels + closes a running foreground child (and re-raises, so the worker actually cancels).

`fork_agent` uses the same foreground lifecycle. Its child-safe live registry
keeps dynamic/MCP tools and `task`, while removing interactive/planning controls
and recursive `fork_agent`.

## Background subagents

A backgrounded subagent (`task(subagent_type=…, prompt=…, run_in_background=true)`) detaches from the parent turn and runs alongside it. The parent turn returns immediately with an agent id (e.g. `agent1`); the bg subagent runs to completion in its own asyncio task. The parent can list, read, and kill it without waiting.

```text
parent turn: returns "started background subagent agent1 (coder) — isolated prompt"
bg agent:    runs in parallel — tool calls fold into its ambient-strip row (live activity)
             lifecycle event → the MCA observes and settles it automatically
```

### The companion tools

Seven `meta` (auto-allowed) tools own the agent lifecycle — for BOTH foreground and background children (they share one registry + id space):

| Tool | What it does |
|---|---|
| `agent_list` | Snapshot of every agent — `fg`/`bg`, lifecycle, outcome, health, mailbox and tool metadata. It never embeds child prose |
| `agent_output(agent_id, wait?, max_wait_ms?)` | Read a finished agent's buffered prose (uncapped — bg agents can be large). On a still-running agent with `wait=true`, blocks up to `max_wait_ms` for completion |
| `agent_kill(agent_id)` | Graceful-then-cancel-then-`aclose` (mirrors `shell_kill`). Works on a running foreground child too (cancels the child without cancelling the parent). Idempotent on already-finished agents |
| `agent_message(agent_id, message, run_in_background?)` | Queue FIFO steering for running/pausing/paused children without resuming a pause, or continue an idle retained child in foreground/background |
| `agent_inspect(agent_id)` | Return structured lifecycle, lineage, liveness, mailbox/tool/usage/output/session metadata; exact diagnostics follow in an untrusted frame |
| `agent_wait(agent_ids, condition?, max_wait_ms?)` | Block on one or more agents when the model cannot proceed without them (`max_wait_ms` defaults to 30s, clamped 10–60s), return snapshots, and claim the lifecycle events it reports. A timed-out wait returns compact liveness rows plus a note restating that settlement arrives on its own — and counts consecutive misses, so a poll loop indicts itself |
| `agent_control(agent_id, action, …)` | Cooperatively pause/resume, promptly interrupt while retaining the session, restart as a linked fresh attempt, or close an idle row |

### The `run_in_background` arg

`coerce_bool` (not bare `bool`) — `"true"`, `"1"`, `"yes"`, `"on"` all enable; everything else falsy. This matches the shell tool's `run_in_background` coercion, so a hallucinated string the model sends by accident still detaches correctly.

### Automatic supervisor attention

Completion, failure, pause, interruption, and stale-health events automatically
regain the main coding agent's attention. During an active turn they are
batched at the next model-round boundary. While idle, Kin starts a serialized
internal continuation with no synthetic user bubble; queued human input wins.

The exactly-once reminder carries event/run ids, lifecycle, outcome, health,
duration, usage, tool count, error availability, and outstanding handles.
Terminal settlements are always listed in full; accumulated health/pause
chatter (for example, hours of watchdog stale/healthy cycles) is capped at
the three newest entries with a collapsed-count note. It never carries child
prose or raw exceptions; use `agent_output` or `agent_inspect` to retrieve
those in an untrusted frame.

Lifecycle delivery is a correctness property and has no off switch. The
retired `KIN_BG_REMINDERS` / `bg_completion_reminders` names have no effect.

Because delivery is guaranteed, polling is explicitly discouraged: the system
prompt, the tool descriptions, and every timed-out `agent_wait` all tell the
main agent that a healthy running child needs nothing from it — do other work
or end the turn, and act when the event arrives. Supervision belongs to the
main agent, not to you: you never need to watch, relay, or nudge a subagent
yourself.

### The ambient strip vs. the agent panel

A bg subagent now has two surfaces, at two different levels of detail:

| Surface | When it's visible | What it shows | What you can do |
|---|---|---|---|
| The ambient strip (below the composer) | Always mounted; shows itself the moment any bg subagent is dispatched, auto-hides a finished row after ~30s | A compact one-line-per-agent summary — status glyph, profile, and **the agent's live activity** (its latest tool call + a call counter, replacing the static prompt preview while it runs; a finished row reverts to the preview + elapsed duration). Capped at 5 rows; a busier session collapses the rest into a `+N more — Ctrl+O` hint | Nothing — it's purely ambient awareness, no kill/dismiss/inspect |
| The agent panel (`Ctrl+O`) | On demand | One focused view at a time. Agent rows lead with status/profile, then show current activity or task, elapsed time, tool-call count, and prompt tokens; bg shells and the tasks DAG have separate counted views | Kill a running agent, dismiss a finished row, open its transcript or raw buffered output |

The strip exists so a bg subagent isn't invisible *between* Ctrl+O checks — before it landed, the only way to notice one had started (or finished) was to open the panel and look. The panel remains the deep-inspection surface; the strip never replaces it.

### The agent panel (Ctrl+O)

The panel is the visual discovery path for `task(...)` — both foreground and background children (DR 0057's unified registry). Without it a bg subagent is invisible, and a running fg subagent is only as visible as the agent-mode `ToolCall` row it spawned from. It mounts as a `ModalScreen` with three counted views, showing only one at a time so empty or secondary sections do not squeeze the useful rows. It opens on the first populated view, with agents first:

| Pane | Contents |
|---|---|
| `agents` | Every child agent — **foreground + background** (the unified `AgentRegistry`). A two-line row leads with profile, human status, placement, elapsed time, and id; the second line shows current activity (or the assigned task) plus available tool-call and prompt-token totals. |
| `shells` | Live + finished bg shells (mirrors `shell_list`) |
| `tasks` | The Tasks DAG (see [Tasks](/docs/kin/concepts/tasks/)) |

Keys:

| Key | Action |
|---|---|
| ++tab++ | Cycle the focused view (agents → shells → tasks → agents) |
| ++shift+tab++ | Cycle backward |
| `x` | Kill a running row / dismiss a finished one (works for fg rows too — Step 1's kill path cancels the child WITHOUT cancelling the parent) |
| `o` | Open the row's raw buffered output in a `ReadOnlyModal` |
| ++enter++ | Open the row's rich transcript in a `TranscriptModal` (falls through to the read-only output for shell/task rows; Enter is never a no-op) |
| ++escape++ | Close the panel |

Ctrl+O opens it (the same priority binding as `shift+tab` / `ctrl+c`, guarded behind modals so it can't pop on top of an open approval / question / plan prompt).

The `BgAgentsBar` (the below-composer strip) deliberately stays bg-only — fg activity already renders live in the transcript's agent-mode `ToolCall` row, so re-listing it on the bar would double-surface. The panel is the deep-inspection surface for both fg + bg.

#### Dipping into an agent (Step 7)

`Enter` on an agent row opens the child's full transcript in a `TranscriptModal` — the rich view, not the raw buffered output (`o`). The modal renders the same widget set `/resume` paints for a saved journal: a rounded "YOU" border for each user prompt, the flat "▌ KIN" assistant blocks with their `Markdown` bodies, and the `ToolCall` rows with their arguments + paired results. The snapshot of `child_session.messages` is taken synchronously at open — `list(child_session.messages)` is a copy under the same event loop, so a snapshot in one tick is a consistent point-in-time view of the child's transcript (no torn reads across user turns). The modal does NOT live-tail; closing-and-reopening refreshes. A running child's transcript IS readable via this path (the `messages` list is the same list the running agent is appending to — it survives across tool calls and tool results, and Step 3's retention keystone keeps it readable for closed children too).

`TranscriptionModal` lives modal-on-modal on top of the AgentPanel (the same shape as `o`'s `ReadOnlyModal` push — a 3-deep screen stack: app → AgentPanel → TranscriptModal). Esc / `q` dismisses back to the panel; the focus return is automatic. The modal is read-only by design — there is no input path into the child from this view (messaging is the MCA's, via `agent_message`; user → agent is deliberately out of scope).

### The capacity cap

The root session's provider-aware capacity is enforced at dispatch time
**against background agents only** (`running_bg_count()`). Local/custom
endpoints default to 3; selected MiniMax/Z.ai plans allow 4–7. A spawn at the
active limit returns, for example:

```
error: at capacity: 5 background agents already running — wait for one to finish or kill one with agent_kill
```

Foreground children do **not** count against this cap — they're bounded by the
same provider-aware semaphore + the depth cap, so a session full of running
foreground subagents can still dispatch background work. The cap remains the
runaway guard; choosing a larger paid plan raises it deliberately through
`/providers`, never from a project file or model action.

### Killing + interrupting

- `agent_kill` / the panel's `x` on a running row → graceful cancel + `aclose` on the child's session (kills its bg shells + cancels pending blockers). Idempotent on a finished agent. Works on a running **foreground** child too: the child is cancelled and the parent's `task` call returns `error: subagent <id> was killed before finishing`, leaving the parent turn free to continue (the parent is NOT cancelled).
- ++escape++ during the parent turn does **not** kill **background** agents — they're designed to outlive a foreground interrupt. (A running **foreground** child IS cancelled by Esc, along with the parent turn.) Only `Session.aclose` (session-end / app exit) tears bg agents down.
- **A finished child parks, it isn't destroyed.** When a subagent's run ends (success or crash), its session stays live on the registry row — the full transcript is retained in `messages`, readable via the panel (`Ctrl+O` → `o` / Enter) and `agent_output`, and resumable later. Closing is deliberate: `agent_kill`, dismissing a finished row, and app exit (`Session.aclose`) each `aclose` the child's session so its lazy `run_code` kernel / headless browser / bg shells don't orphan. A closed row's transcript stays readable (closing tears down processes, not data).
- **Each subagent also writes its own journal** (hidden from `/resume` / `--continue` — see [Sessions](/docs/kin/guide/sessions/#subagent-journals-are-hidden)).

### When a subagent fails

A foreground `task` call can fail in a few ways, and each one produces a
structured, id-bearing result so the parent can tell *what* happened and
*where* the full transcript lives. The result is ALWAYS prefixed with
`error:` — that prefix is the cross-backend `is_error` mechanism
(`loop._finalize` auto-detects it; the Anthropic wire carries
`is_error: true`, the OpenAI wire has no error field at all, so the text
prefix is the only signal that reaches the model on **both** wires). Full
shapes are in [Subagents — When a subagent fails](/docs/kin/guide/subagents/#when-a-subagent-fails);
the short version:

- **`error` (wire death after retries)** — `error: subagent <id> failed
  mid-run — partial output below; transcript retained (agent_output("<id>"))`
  + the partial prose. **A mid-run wire death surfaces the partial prose
  with a marker** — the parent can no longer mistake a half-answer for a
  whole one (the silent-partial bug closed by DR 0059). Before DR 0059 a
  fg child that died mid-stream had `done_reason=None` (the fg path dropped
  the `done` event) and the partial prose surfaced as the complete answer
  with no marker.
- **`turn_cap` (a custom profile hit its positive `max-turns`)** — same
  shape, head carries the cap value (`hit its turn cap (N turns)`).
  Bundled profiles are unlimited; this outcome exists for an operator-imposed
  custom bound. Replaces the bare `"(the subagent produced no output)"`
  sentinel.
- **`loop_detected` (doom-loop guard)** — same shape, named accordingly.
- **`crashed` (a raw harness exception)** — `error: subagent <id> crashed:
  {exc} — transcript retained (agent_output("<id>"))`. The child parks, NOT
  closes (see the "finished child parks" note under Killing + interrupting
  above), so the transcript hint is true.
- **`killed` (`agent_kill` / panel `x`)** — `error: subagent <id> was
  killed before finishing`. The parent turn **continues**.

The full transcript is always on the row via `agent_output("<id>")` (or
the panel — `Ctrl+O` → `o` / Enter) for every failed row. The 32&nbsp;KB
cap is signalled by a `truncated` flag on the child's emit, not by
string-sniffing — the shaper reads the flag and appends the id-bearing hint
when the cap fires.

The row's `status` + `done_reason` mirror the bg path: a wire death is
`status=error` + `done_reason=error`; a turn cap is `status=ok` +
`done_reason=turn_cap`. The `agent_list` tool surfaces `done_reason` when
it isn't `stop`.

Every failure string also carries the resume hint
`agent_message("<id>", "<next instruction>")` — a parked child has a real
way back in (the [turn-completion resume model](/docs/kin/guide/subagents/#continuing-a-parked-subagent-agent_message)),
so a failed `task` call hands the model the recovery path in the same
read as the transcript hint. The `stop` branch deliberately omits the
resume hint — clean stop is a completion, not a failure to recover from.

## Profile-as-session: `--agent <name>`

```bash
kin --agent researcher            # main session runs as the researcher profile
kin --agent coder --workdir ~/..  # the main thread = coder, against a path
```

The CLI walks the same `Session` factory with the profile's tools, the profile's system prompt, and the parent's `KIN_*` / `settings.toml` config (mode, model, base_url, sandbox — all honored). `Session.from_profile` reuses the same profile loader the `task` tool uses (`subagents.resolve_for(workdir)`), so the two paths can't drift on profile resolution.

### What's stripped

Interactive-only tools (`ask`, `present_plan`) are stripped from a profile-as-session — a focused agent is not its own question-asker when it IS the main thread. The same strip applies to bg subagents (see `TaskTool.run`).

### The launch flow

1. `kin --agent researcher` → `cli.main` reads `--agent` and resolves the profile.
2. `Session.from_profile` populates `SUBAGENTS` against the workdir, scopes the registry to the profile's tools, and composes `system = SYSTEM_PROMPT + profile.system_prompt`.
3. The same `app.bind_client(harness)` + `app.run()` path as a normal launch.
4. The top bar / banner still show the model + workspace, so you can tell at a glance which agent you're running.

### No-TTY caveat

`--agent` is a TTY-only path — it launches the Textual UI, which needs a terminal. If `stdin.isatty()` is false (a non-interactive shell, a piped launch), the CLI refuses with a clear error. If you need a non-interactive `--agent` run, drive the harness directly via a Python `from kin.harness.session import Session` + `Session.from_profile(...)` call (that's the same factory the CLI uses).

### Resuming

`--resume <id>` + `--agent <name>` is **rejected at the CLI** (the two flags are mutually exclusive in `cli.py`'s arg validation): an agent session is a fresh run, not a replay. If you want to resume a session, run `kin --resume <id>` without `--agent`; the saved journal meta determines the model + base_url. To run a profile against a new workdir, use `kin --agent <name>` standalone.

## The planner agent

`planner` is a bundled, read-only profile that drafts the actual plan content. Rather than researching and writing a plan inline, the top-level model dispatches it — `task(subagent_type='planner', prompt=…)` — the same way it dispatches any other subagent. It doesn't see the parent conversation, only the `prompt` it's given.

Its toolset is research-only: `read_file`, `glob`, `grep`, `ls`, `web_fetch`, `web_search`, `search_workspace`, `todos`, plus `write_plan`. It researches the codebase (and the web, if useful) until it understands what needs to change — reading every file it will name, tracing call sites, checking the repo's own guidance docs — then writes a thorough, **self-contained** plan: goal, context with `file:line` evidence of how the code works today, the chosen design plus rejected alternatives, files to touch/not touch with exact anchors, constraints and conventions, an ordered task list with per-task checks, risks and edge cases, acceptance criteria, a verify command, and an empty issue log — via `write_plan`, whose first call auto-enters the [planning freeze](/docs/kin/guide/modes-and-permissions/#planning) on the top-level session. The bar is deliberate: on **Approve, clear & re-inject** the plan becomes the executor's *only* context — and the executor may be a smaller model — so it must carry everything execution needs, written for a reader who has never seen the repo. It never calls `present_plan` itself — only the top-level agent can present a plan to you — so its final message is just the plan's path plus a short pointer to 2-3 files worth spot-checking, letting the orchestrator validate before presenting. The profile lives at `src/kin/harness/defaults/agents/planner.md`.

## The critic agent

`critic` is a bundled, read-only profile used by the [plan lifecycle](/docs/kin/guide/modes-and-permissions/#planning). When you pick **Review plan first** in the `present_plan` approval modal, the top-level model dispatches `critic` itself (via `task(subagent_type='critic', ...)`) against the tracked plan file and returns its critique; you stay in the planning freeze while it applies fixes with `write_plan` and re-presents (only **approve** lifts the freeze).

It is built to stress-test, not rubber-stamp:

- **Read-only toolset** — `read_file`, `glob`, `grep`, `ls`, `web_fetch`, `web_search`, `todos`. It can read the codebase the plan targets (and the web) to ground every objection, but it has no edit or shell tools, and it inherits the planning freeze besides — so it cannot act regardless.
- **Adversarial, attribution-obscured framing** — the plan is presented as "a plan under review," never "your plan" (a model criticizes an external artifact far harder than its own work). It is told to assume at least one critical flaw and find it.
- **A six-dimension rubric** — it leads with the first step that fails (with evidence), then reviews against SEQUENCING, ASSUMPTIONS, REVERSIBILITY, COMPLETENESS, CODEBASE_FIT, and SELF_CONTAINMENT (could a stranger execute this plan against a cleared context?), and ends with the single highest-priority fix. A single pass.

The critique comes back as prose (not structured JSON) because it is consumed two ways at once — re-injected as context for the model to act on, and shown to you — and prose is the model-agnostic floor across kin's real fleet. The profile lives at `src/kin/harness/defaults/agents/critic.md`; override it like any other bundled profile by dropping a `critic.md` in a higher-priority [discovery root](#discovery).

`critic-code` is a sibling profile, bundled alongside `critic` — same
read-only toolset, same adversarial, attribution-obscured framing, but it
reviews finished code or output instead of a plan, against a different
five-dimension rubric: CORRECTNESS, EDGE_CASES, SECURITY, PERFORMANCE, and
MAINTAINABILITY. It isn't part of the plan lifecycle; the bundled
[`/critique`](/docs/kin/guide/workflows/#save-a-run-as-a-reusable-command) `kind:
workflow` slash command dispatches three of them in parallel, each owning a
subset of the rubric, and synthesizes their findings by severity; the bundled
`/revise` command uses it as the rubric grader in its draft → grade → revise
loop (each grader reads the published draft by artifact ref).

`explorer` is a bundled, read-only profile for codebase orientation — it
answers "how does this codebase work" with a fixed 6-section orientation
(Purpose / Entry points / Key files / Conventions / Answers / Unknowns),
cites `path:line` evidence, and never pastes file bodies. Its toolset is
local-only — `read_file`, `glob`, `grep`, `ls`, `search_workspace`, `todos`,
no web — which keeps it disjoint from `researcher` (web) and from `coder`
(edits). Dispatch it when the parent needs to ground a decision in the
codebase without burning context on broad reads; it's the canonical
context-isolation exemplar and the fan-out worker the bundled `/init`
and [`/research`](/docs/kin/guide/workflows/#save-a-run-as-a-reusable-command)
commands dispatch (`/research` scales 1–5 explorer lanes to the question's
complexity and has each lane publish its findings as an artifact handle).

`security-auditor` is a bundled, read-only profile that stress-tests
finished work against a six-dimension security rubric — INJECTION,
INPUT_HANDLING, AUTH, SECRETS, SUPPLY_CHAIN, CONFIG — and is the
structural sibling of `critic-code`. Two rules distinguish it from a
generic code review: every finding must name the attack path (where
untrusted data enters → what it reaches; a pathless hardening is at
most `low` severity), and severity is graded as exploitability × impact,
not how scary the code reads. Dispatch it independently via `task` when a
parent agent wants a security-focused adversarial review separate from
the broader `critic-code` rubric.

`researcher` is the bundled, read-only web-research lane — `read_file` plus
the [web tools](/docs/kin/guide/web-tools/) and `cite_check`, no edits, no shell.
Dispatch it for a fast, sourced answer to one question; the bundled
[`/deep-research`](/docs/kin/guide/deep-research/) `kind: workflow` command fans
several of them out in parallel (with an adversarial `critic` review and a
citation-liveness gate) when the question deserves a full multi-source
report.

`rig` is the bundled, non-interactive excursion lane for Kin's persistent
computer. It is scoped to `rig`, `rig_shell`, `rig_memory`, and `todos`; it
returns a distilled answer and records durable machine knowledge before it
finishes. Credentials stay on the human handoff path — if a login is required,
the profile stops and asks the parent to have the operator take control. See
[Rig](/docs/kin/guide/rig/) for the computer boundary and control flow.

## Discovery

Profiles are loaded from markdown+frontmatter on disk. The five roots, highest priority first:

1. `<workdir>/.kin/agents/`
2. `<workdir>/.claude/agents/`
3. `~/.kin/agents/`
4. `~/.claude/agents/`
5. the bundled defaults at `src/kin/harness/defaults/agents/` (general / researcher / coder / planner / critic / critic-code / explorer / rig / security-auditor)

The full schema + a worked example are in [Subagents](/docs/kin/guide/subagents/#agent-profiles).
