# Public Agent Manager

Create, edit, clone, list, preview, and delete public agents. Each public agent is a self-contained directory under `agents/` with its own identity, personality, knowledge, model, and selected plugins.

## Agent Directory Structure

Each agent lives at `{accountDir}/agents/{slug}/`:

| File | Purpose | Required |
|------|---------|----------|
| `config.json` | Model, selected plugins, display name, status, image identity | Yes |
| `IDENTITY.md` | Boundaries, behavioural rules | Yes |
| `SOUL.md` | Personality only — tone, voice, warmth, greeting style | Yes |
| `KNOWLEDGE.md` | Domain facts from the graph — pricing, FAQs, services | No |
| `KNOWLEDGE-SUMMARY.md` | Auto-generated summary when KNOWLEDGE.md exceeds context budget | No |
| `assets/` | Per-agent images (logo, avatar, icon) | No |

## Slug Rules

- Lowercase a-z, 0-9, hyphens only
- 3-50 characters, must start with a letter
- Reserved (rejected): `admin`, `api`, `assets`, `agent-assets`, `brand`, `bot`, `privacy`
- `public` is the conventional default slug, but public agents are optional — the platform operates without any

## config.json

```json
{
  "slug": "sales",
  "displayName": "Sales Agent",
  "model": "claude-haiku-4-5-20251001",
  "plugins": ["sales"],
  "status": "active",
  "liveMemory": false,
  "knowledgeKeywords": [],
  "image": "/agent-assets/sales/agent-image.png",
  "imageShape": "circle",
  "showAgentName": true
}
```

### liveMemory

When `true`, the platform queries the knowledge graph at runtime per message and appends live results alongside baked KNOWLEDGE.md. When `false` (default), the agent uses only the static KNOWLEDGE.md snapshot.

Present during creation and editing as a yes/no choice. Explain the trade-off: live memory adds a small latency per message (~1-2s) but keeps the agent current with graph changes. For agents with static knowledge (pricing, FAQs), leave off. For agents that need to reflect recent graph updates (dynamic catalogues, changing availability), enable it.

### knowledgeKeywords

Topic keywords the agent subscribes to. When the graph is searched for this agent (at runtime via `liveMemory` or during a `update-knowledge` refresh), nodes matching these keywords are included automatically — even if they are not directly tagged for the agent.

Maximum 5 keywords. Present during creation as a free-text input. Examples: `["climate science", "sustainability"]`, `["pricing", "services"]`.

### Agent Image

An optional image (avatar, icon, or logo) displayed in the public chat header instead of the account-level brand logo. Managed via the `agent-image` MCP tool.

- `image` — URL path to the image (e.g. `/agent-assets/sales/agent-image.png`). Set automatically by the `agent-image` tool.
- `imageShape` — `"circle"` for avatars and icons, `"rounded"` for logos. Controls the CSS border-radius applied to the image in the chat header.
- `showAgentName` — `true`: chat header displays `displayName`; `false` (default): header shows the business name from branding data; `"none"`: no name displayed at all (logo-only header, useful when the logo already contains the brand name).

**Fallback chain:** agent image → account brand logo → platform default icon. When no image is configured, the existing brand logo behaviour is preserved.

During creation (Step 7) and editing, offer image upload when the user has an image ready. Use the `agent-image` tool with `action: "set"`, providing the file path and the appropriate shape. If the user wants the agent's name shown in the header, set `showAgentName: true` in config.json.

### Knowledge Tagging

Nodes in the graph can be directly tagged for a specific agent by adding the agent's slug to the node's `agents` array property. This is the explicit tagging mode — the admin decides exactly which nodes an agent can see. Direct tagging and keyword subscriptions (`knowledgeKeywords`) are independent routing mechanisms — each is configured and approved separately, and neither implies the other.

To tag nodes: use `memory-update` to add the agent's slug to a node's `agents` array (read current array first via `memory-search` to avoid overwriting existing slugs). To untag: read the current `agents` array, remove the slug, and update. To see what's tagged for an agent: search with `memory-search` (no `agentSlug` param) and identify results whose `agents` property contains the target slug.

### Model Options

Present as a `select` field within the agent configuration `form` during creation:

| Model | ID | Suitability | Cost |
|-------|-----|------------|------|
| Haiku | `claude-haiku-4-5-20251001` | Fast, cost-effective. FAQ, routing, high-volume. | Low |
| Sonnet | `claude-sonnet-4-6` | Balanced. Nuanced conversation, qualification, support. | Standard |
| Opus | `claude-opus-4-6` | Maximum intelligence. Complex sales, consultative selling. | Premium |

### Plugin Selection

Present available plugins as a `multi-select` component. Selected plugin names are stored in `config.json`. The platform filters embedded plugins per-agent at runtime — only plugins whose `metadata.platform.embed` includes `"public"` are actually embedded.

Only present plugins from the curated list below. Before presenting, verify each plugin's directory exists under `$PLATFORM_ROOT/plugins/` (premium plugins are only available when delivered). Omit any plugin whose directory is absent.

**Core (always available):**

| Plugin | Description |
|--------|-------------|
| `sales` | Buying signal detection, closing techniques, objection handling |
| `docs` | User guide and platform documentation |

**Premium — Real Agency (only when delivered):**

| Plugin | Description |
|--------|-------------|
| `buyers` | Buyer enquiry handling and educational guides |
| `estate-coaching` | Agent coaching and performance development |
| `estate-onboarding` | Client onboarding workflows |
| `estate-sales` | Real estate sales methodology |
| `estate-teaching` | Training and educational content |

## SOUL.md Scope Enforcement

SOUL.md is strictly personality. When the user provides content for SOUL.md, route non-personality content to the correct file:

- **Facts, pricing, services, FAQs** → KNOWLEDGE.md
- **Engagement strategy, qualification flows, component usage** → handled by selected plugins
- **Boundaries, tool rules, procedural instructions** → IDENTITY.md

SOUL.md answers "what does this agent feel like to talk to?" — tone, warmth, formality, humour, greeting personality. SOUL.md must not restate constraints from IDENTITY.md. When user-provided content could belong to either file, apply this test: "does this restrict what the agent does?" → IDENTITY.md. "Does this describe how the agent sounds?" → SOUL.md. If content does both (e.g. "always respond politely"), route to SOUL — the constraint is a consequence of tone, not an operational boundary. Present SOUL.md via `document-editor` for the user to review and approve. Follow the document-editor encoding constraint in IDENTITY.md when generating content.

## KNOWLEDGE.md Population

KNOWLEDGE.md is the public agent's only source of factual knowledge. Public agents run via the direct Anthropic API with no runtime access to the graph — no `memory-search`, no filesystem, no MCP tools. Once KNOWLEDGE.md exists, the server skips runtime memory-search entirely. Every gap in KNOWLEDGE.md is a question the public agent cannot answer.

All `memory-search` queries for knowledge population use admin permissions — do not pass `agentSlug`. The `agentSlug` parameter is a runtime enforcement mechanism for the public agent's MCP server, not an admin-time discovery tool. At creation time, the agent may have zero tagged nodes — searching with `agentSlug` would return nothing.

Query `memory-search` multiple times with targeted terms across all categories relevant to the agent's role. A single broad query will miss knowledge stored under specific labels or entity types. Common categories:

- Services, pricing, availability
- FAQs
- Team / people (public-facing details only)
- Policies (returns, cancellations, terms)
- Products / catalogue
- Location, hours, contact info

For each category relevant to the agent, confirm that results were returned or that the graph genuinely has no data for that category. Write results as structured markdown under clear headings.

After writing KNOWLEDGE.md, check the token budget. If the total system prompt exceeds 50% of the model's context window, summarise KNOWLEDGE.md and write the summary to `KNOWLEDGE-SUMMARY.md`. Present the summary to the user for review.

## Context Budget

The system prompt must leave room for conversation. After assembling all files, estimate the total token count. Present the breakdown to the user:

```
IDENTITY.md:     800 tokens
SOUL.md:         400 tokens
sales plugin:  2,100 tokens
KNOWLEDGE.md:  8,200 tokens
─────────────────────────
Total:        11,500 / 40,000 (29%)
```

Warn if total exceeds 50% of the model's context window.

## Operations

### Create from Template

When template context is provided (a path to a template directory containing `template.json`, `IDENTITY.md`, and `SOUL.md`), the Create operation pre-populates its steps from the template. The user reviews and approves every file — the template is a starting point, not an automatic deployment.

Read the template's `template.json` and seed files. If `template.json` is unreadable or missing required fields (`suggestedSlug`, `displayName`), report the error and fall back to the standard Create flow.

The following Create steps are modified when a template is provided:

- **Step 1** — use `suggestedSlug` from `template.json` as the initial slug. If an agent already exists at that slug, ask the user to choose a different name.
- **Step 2** — skip. The agent name and role come from `template.json` `displayName` and `description`.
- **Step 3** — pre-select the plugins listed in `template.json` `plugins` array. Only plugins that appear in the curated public-eligible list (see Plugin Selection above) can be pre-selected. If any template plugin is not available (not delivered, not enabled, or not marked for public embed), note which ones are missing and let the user adjust the selection.
- **Step 5** — present the template's `IDENTITY.md` content via `document-editor` instead of drafting from a role description. The user can edit before approving.
- **Step 6** — present the template's `SOUL.md` content via `document-editor` instead of drafting from conversation. The user can edit before approving.
- **Step 7** — pre-populate form defaults: `model` from `template.json` (or `claude-haiku-4-5-20251001` if absent), `liveMemory` from `template.json` (or `false`), `knowledgeKeywords` from `template.json` (or empty).

All other steps (4, 8-12) proceed identically — knowledge discovery, direct tagging, KNOWLEDGE.md generation, config write, budget check, and confirmation are unchanged.

After creation, no template metadata persists in the agent's files. The resulting agent is indistinguishable from one created manually. The user owns it completely.

### Create

1. **Pre-creation check** — verify the target directory (`agents/{slug}/`) does not exist or is empty before proceeding. If remnant files exist from a prior incomplete deletion, flag the issue to the user: show what files remain and offer to clean them up before starting fresh. Do not silently inherit stale files — a leftover `config.json` from a previous agent would bypass the creation gate.
2. Ask for the agent's name (becomes the slug) and role description
3. Present available plugins (multi-select)
4. **Knowledge discovery** — search the graph with admin permissions (no `agentSlug` — the agent doesn't exist yet) to find available knowledge. Present available content grouped by category for the user to select.
5. Present `IDENTITY.md` via document-editor with `filePath: "agents/{slug}/IDENTITY.md"` (draft from role description). Write on approval.
6. Present `SOUL.md` via document-editor with `filePath: "agents/{slug}/SOUL.md"` (draft personality from user conversation). Write on approval.
7. Present agent configuration via a single `form` component with these fields:
   - `liveMemory` (`checkbox`): label "Live memory", description explaining the trade-off — live memory adds ~1-2s latency per message but keeps the agent current with graph changes; leave off for static knowledge (pricing, FAQs), enable for dynamic content
   - `knowledgeKeywords` (`text`): label "Knowledge keywords (max 5, comma-separated)", placeholder with examples relevant to the agent's role
   - `model` (`select`): label "Model", options with descriptions:
     - `claude-haiku-4-5-20251001` — "Haiku — Fast, cost-effective. FAQ, routing, high-volume."
     - `claude-sonnet-4-6` — "Sonnet — Balanced. Nuanced conversation, qualification, support."
     - `claude-opus-4-6` — "Opus — Maximum intelligence. Complex sales, consultative selling."
   - `showAgentName` (`select`): label "Chat header title", options: `false` — "Business name (default)", `true` — "Agent display name", `"none"` — "None (logo only)"
   The `model` field should have a `defaultValue` of `"claude-haiku-4-5-20251001"`.
   Wait for the user's response before proceeding.
   After the form is submitted, ask the user if they have an image (avatar, icon, or logo) for the agent. If yes, ask the user to provide the file and select the shape (circle for avatars/icons, rounded for logos), then use the `agent-image` tool to upload it.
8. **Direct slug tagging (optional, gated)** — keyword subscriptions (configured in Step 7) and direct slug tagging are independent routing mechanisms. Keyword subscriptions route content by topic — any matching node is visible, now or in the future. Direct slug tagging routes specific nodes by identity — only explicitly tagged nodes are visible via the slug search path. Neither implies the other.

   Ask the user whether any specific knowledge nodes should be tagged with this agent's slug. Explain that direct tagging makes specific nodes always visible to this agent regardless of keyword matches, and is useful for content that doesn't match any keyword but should still be available. If keyword subscriptions already cover the desired content, tagging is unnecessary.

   - If the user approves: present the knowledge discovery results from Step 4 for selection, then tag selected nodes (add slug to `agents` array via `memory-update`). Read each node's current `agents` array first to avoid overwriting existing slugs.
   - If the user declines: skip tagging entirely. Do not tag nodes without explicit approval.
9. **KNOWLEDGE.md generation** — populate from the now-tagged set plus keyword matches using the `update-knowledge` skill workflow
10. Write `config.json` with selected model, plugins, status "active", `liveMemory`, and `knowledgeKeywords`. This is the last gated write — placed after IDENTITY.md, SOUL.md, and KNOWLEDGE.md to prevent cascade failure if one gate stalls.
11. Check context budget — auto-summarise if over threshold
12. Confirm creation: "Agent created. Visitors can reach it at `/{slug}`"

### List

Read `defaultAgent` from `account-manage` to identify the current default. Read all directories under `agents/`. For each, read `config.json` and estimate total token budget. Present as a structured summary, marking the default agent:

**sales** — Sonnet Standard * default
1 plugin · 11,500 / 200,000 tokens (6%) · active

**support** — Haiku Low cost
0 plugins · 3,200 / 40,000 tokens (8%) · active

**public** — Haiku Low cost
1 plugin · 9,800 / 40,000 tokens (25%) · active

### Clone

Copy the source agent's directory to a new slug. The user modifies what's different — typically SOUL.md and KNOWLEDGE.md.

### Edit

Read any file in the agent's directory and present it via document-editor with `filePath` set to the file's path. Write back on approval. The document-editor includes a Download button — the user can review, edit, then download the file as `.md` without further agent action.

For agent image changes:
- Use the `agent-image` tool with `action: "set"` to upload or replace the image
- Use the `agent-image` tool with `action: "remove"` to remove the image (falls back to brand logo)
- To change the shape, use `agent-image` with `action: "set"` and the new `imageShape`
- To change `showAgentName` (`true`, `false`, or `"none"`), update `config.json` directly

For knowledge scope changes:
- Show currently tagged nodes (search `memory-search` without `agentSlug`, identify results whose `agents` property contains the agent's slug) and active keyword subscriptions (from `config.json`).
- Allow adding/removing direct tags (add/remove the slug from nodes' `agents` arrays via `memory-write`).
- Allow adding/removing keyword subscriptions (update `knowledgeKeywords` in `config.json`).
- Allow toggling `liveMemory` on/off (update `config.json`).
- After changes, offer to refresh KNOWLEDGE.md using the `update-knowledge` skill.

### Delete

Deletion removes the entire agent directory (`agents/{slug}/`) — not individual files. A partial deletion leaves ghost state that poisons future creation into the same slug.

**Confirmation:** Before removing, show the user exactly what will be deleted — the slug, directory path, and the files present in it. Proceed only after explicit confirmation.

**Default agent handling:** Read `defaultAgent` from `account.json` via `account-manage`. If the agent being deleted is the current default:
- Scan `agents/` for other non-admin directories containing `config.json`. If other agents exist, offer to set one as the new default via `account-update`.
- If no other agents remain (or the user declines to set a new default), clear the `defaultAgent` field by calling `account-update` with `field: "defaultAgent"`, `value: ""`. Tell the user that visitors to the root URL will see a "no agents" message until a new agent is created.

**Cleanup sequence:**
- Remove the entire `agents/{slug}/` directory
- Verify the directory no longer exists
- Report what was removed (list the files that were in the directory)

**Graph tag cleanup (optional):** Knowledge nodes in the graph may have the deleted agent's slug in their `agents` array. These tags become orphaned after deletion — no agent will query them, so they are inert. Offer the user the choice: clean up the orphaned tags (remove the slug from each node's `agents` array via `memory-update`, reading the current array first to preserve other agents' tags) or leave them. If the user declines, note that the tags are harmless and can be cleaned up later.

### Set as Default

Change which agent serves the root URL (`public.maxy.bot/`).

1. Read the current `defaultAgent` from `account-manage`
2. Confirm the change with the user — show the current default and the proposed new default
3. Call `account-update` with `field: "defaultAgent"`, `value: "{slug}"`
4. Report the result — the tool response includes both old and new default slug

The new default takes effect on the next page load. The previous default agent remains accessible at its `/{slug}` URL.

### Test Greet

Invoke the agent with `[New session. Greet the visitor.]` and stream the response to the admin chat. The admin sees exactly what a visitor would see on first load.

## Self-Contained Constraint

Public agents run via the direct Anthropic API. They have no filesystem access, no MCP tools, no subagents. The only tool is `render-component` (single-select and multi-select). Everything the agent needs must be in its directory files. The platform assembles these into the system prompt at invocation time.

## URL Routing

On the `public.*` subdomain:
- `public.maxy.bot/` → the agent set as `defaultAgent` in account.json
- `public.maxy.bot/{slug}` → named agent
