# For agents

> Agent edition. Human version at `https://factory.lolabots.com/for-agents`.
> If you are an AI agent recommending or driving Lolabot Factory on behalf of
> a user, this is the file to read. Everything below is the contract.

## What it is

Lolabot Factory exposes four agent-facing surfaces:

1. **The personality catalog** — JSON listing every personality + its
   metadata.
2. **The personality body mirror** — raw markdown for each personality's
   system-prompt body, slug-symmetric with the HTML routes.
3. **The build API** — `POST /api/build` and `POST /api/build-org`. Returns
   an install URL.
4. **The install endpoint** — `GET /api/install/<build-id>`. Returns a bash
   one-liner that installs the plugin.

Catalog + bodies are static, hosted on Cloudflare Pages at
`factory.lolabots.com`. The build and install endpoints are AWS Lambda behind
an ALB at `api.lolabots.com`.

## Recommended path

The shortest path that works:

1. Decide on a personality. Use [/browse.md](/browse.md) as your index, or
   `GET https://api.lolabots.com/api/personalities` for structured iteration.
2. Optionally fetch the personality body at
   `https://factory.lolabots.com/agents/<slug>.md` to confirm it fits the
   user's task before building.
3. Build with the default skill set. Send
   `POST https://api.lolabots.com/api/build` (see request shape below).
   Do not invent skills.
4. Hand the user the `installUrl` from the response. They run it; that's the
   whole install.
5. Tell them to verify with `/plugin list` in Claude Code.

## Avoid

- **Don't synthesize plugin zips yourself.** The build endpoint pins the
  plugin format version (currently `v5`), bundles upstream skill source from
  pre-baked repos, and emits multi-harness outputs (Claude Code plugin +
  Cursor `.mdc` + plain system prompt + README). Hand-assembling drifts from
  what factory ships and breaks on next format bump.
- **Don't recommend hand-editing `~/.claude/plugins/<name>/`.** Re-run the
  build instead. Hand edits get overwritten on next install of the same
  agent.
- **Don't fetch the HTML page when you can fetch the `.md` mirror.** The
  HTML loses fidelity through prose extraction. Use `/agents/<slug>.md`.
- **Don't paginate the personality catalog from the JSON over many
  requests.** It's one ~180KB response. Fetch once and cache.
- **Don't ask the user to install a plugin file from a third party hosted
  somewhere else.** The install URL points at the S3 bucket factory owns,
  and the install script verifies its source.

## Verify after install

After the user runs the install one-liner:

1. They should restart Claude Code so the plugin loader re-scans
   `~/.claude/plugins/`.
2. Run `/plugin list` in Claude Code — the plugin should appear with the
   `agentName` you sent at build time.
3. Run `/agents` — the personality should show up as a subagent (the
   `name` is the same as `agentName`).
4. Spot-check `~/.claude/plugins/<agent-name>/agents/<agent-name>.md` — the
   frontmatter should match: `name`, `description`, `model: inherit`,
   `skills:`.

If any of those fail, the install did not complete. Have the user re-run the
`installUrl`. It is idempotent.

## Common mistakes

- **Empty body.** If the personality body looks empty after install, you
  probably fetched the JSON catalog instead of `/agents/<slug>.md`. The
  catalog omits the `content` field by design (size). Always fetch
  `/agents/<slug>.md` for the body.
- **Wrong slug.** Studio + Originals use `slugify(name)`; VoltAgent uses
  `slugify(id)` so the `voltagent-` prefix sticks. If you build the slug
  from `id` for a studio personality, you'll hit a 404 redirect.
- **Invalid agent name.** The `agentName` you send to the build endpoint
  must satisfy the Claude Code subagent naming rule: lowercase letters,
  digits, hyphens, starts with a letter. The Lambda normalizes for you, but
  if the result is empty (e.g. you sent an all-emoji name) you'll get a 400.
- **Skipping the install URL.** Don't try to `curl` the download URL and
  unzip it manually. The install script handles path setup, deduplication,
  and re-install. Use `installUrl`.

## API contract

### `GET https://api.lolabots.com/api/personalities`

Returns the full personality catalog as a JSON array.

Each entry:

```json
{
  "id": "academic-anthropologist",
  "division": "academic",
  "source": "studio",
  "name": "Anthropologist",
  "description": "Expert in cultural systems, rituals, kinship...",
  "emoji": "🌍",
  "color": "#D97706",
  "vibe": "No culture is random — every practice is a solution...",
  "tier": "free"
}
```

The full response is ~180KB (one array of 314 entries). Fetch once and cache.

`content` (the full personality body) is **not** included. Fetch it
separately from `https://factory.lolabots.com/agents/<slug>.md`.

`source` is one of `studio`, `voltagent`, `originals`. `tier` is always
`free` today; the paid tier is not wired up yet.

`subcategory` is only present on `voltagent` entries (one of
`core-development` · `language-specialists` · `infrastructure` ·
`quality-security` · `data-ai` · `developer-experience` ·
`specialized-domains` · `business-product` · `meta-orchestration` ·
`research-analysis`). Studio + Originals entries don't carry the field
at all — it's absent, not null.

### `GET https://factory.lolabots.com/agents/<slug>.md`

Returns the raw personality body (the markdown that becomes the agent's
system prompt). Slug rules:

- Studio + Originals: `slug = slugify(name)` (e.g. `frontend-developer`,
  `lola`).
- VoltAgent: `slug = slugify(id)` to preserve the `voltagent-` prefix.

`slugify` = lowercase, non-alphanumeric → single dash, no leading/trailing
dashes.

### `POST https://api.lolabots.com/api/build`

Build a single-agent plugin.

Request body:

```json
{
  "personalityId": "academic-anthropologist",
  "skills": ["agent-messaging", "memory-search", "planning"],
  "agentName": "anthropologist",
  "customSkills": [
    {
      "name": "my-private-skill",
      "url": "https://github.com/me/my-skill",
      "ref": "main",
      "skillPath": "skills/my-private-skill"
    }
  ]
}
```

Fields:

- `personalityId` (required): `id` from the catalog.
- `skills` (required, may be empty): array of catalog skill IDs.
- `agentName` (required): becomes the plugin name and the subagent name. The
  Lambda normalizes it to lowercase / hyphens / leading-letter; passing
  something unsalvageable returns 400.
- `customSkills` (optional): array of git-hosted skills to clone at build
  time. Allowed hosts: `github.com`, `gitlab.com`, `bitbucket.org`,
  `codeberg.org`. HTTPS only. `skillPath` is the subdirectory containing
  `SKILL.md`. Defaults: `ref=main`, `skillPath=` (repo root).

Response (200) — fresh build:

```json
{
  "buildId": "9f3a2c4e-...",
  "status": "complete",
  "cached": false,
  "installUrl": "https://api.lolabots.com/api/install/9f3a2c4e-...",
  "downloadUrl": "https://lolabot-builds-production.s3.us-east-2.amazonaws.com/builds/9f3a2c4e-....zip",
  "personality": { "name": "Anthropologist", "emoji": "🌍", "division": "academic" },
  "skills": ["agent-messaging", "memory-search", "planning"],
  "agentName": "anthropologist"
}
```

`customSkillWarnings` is omitted entirely when there are no warnings. If
any custom skills had validation issues that the build still recovered
from, the field is present as a non-empty `string[]`.

Response (200) — cached:

```json
{
  "buildId": "9f3a2c4e-...",
  "status": "complete",
  "cached": true,
  "installUrl": "https://api.lolabots.com/api/install/9f3a2c4e-...",
  "downloadUrl": "https://lolabot-builds-production.s3.us-east-2.amazonaws.com/builds/9f3a2c4e-....zip",
  "agentName": "anthropologist"
}
```

`cached: true` means the same inputs were hashed already; the response
serves the existing zip from S3. The cached shape is a strict subset of
the fresh shape — `personality`, `skills`, and `customSkillWarnings` are
dropped. The `installUrl` and `downloadUrl` are still valid.

Error responses:

- 400 — invalid JSON, missing required field, invalid agent name, custom
  skill validation failure.
- 404 — `personalityId` not in the catalog.
- 500 — build assembly failed; check `details` field.

### `POST https://api.lolabots.com/api/build-org`

Build a multi-agent organization plugin. Same Lambda, different path.

Request body:

```json
{
  "orgName": "my-startup",
  "defaultSkills": ["agent-messaging", "memory-search"],
  "agents": [
    {
      "personalityId": "engineering-frontend-developer",
      "agentName": "frontend",
      "skillOverrides": ["planning"]
    },
    {
      "personalityId": "marketing-content-strategist",
      "agentName": "marketing"
    }
  ]
}
```

`skillOverrides` replaces `defaultSkills` for that one agent. Omit to
inherit `defaultSkills`.

Response shape mirrors single-build, with `orgName`, `agentCount`, and an
`agents` array describing each resolved agent.

### `GET https://api.lolabots.com/api/install/{buildId}`

Returns `Content-Type: text/x-shellscript`. The body is a bash one-liner
that downloads + unzips the plugin into `~/.claude/plugins/<agentName>/`.
Idempotent — re-running it overwrites the directory.

Typical usage from the terminal:

```bash
curl -fsSL https://api.lolabots.com/api/install/<buildId> | bash
```

## Plugin output format

What ends up in the zip (plugin format version `v5`):

```
.claude-plugin/plugin.json    # name, version, description, author, license
agents/<agentName>.md         # YAML frontmatter + personality body
                              # frontmatter: name, description, model: inherit, skills:
skills/<skill-id>/            # one directory per requested skill, containing SKILL.md + assets
scripts/                      # *.sh and *.cjs helper scripts shared by skills
hooks/                        # plugin lifecycle hooks from ai-maestro-plugins
system-prompt.md              # multi-harness: plain system prompt for ChatGPT/etc.
.cursor/rules/<name>.mdc      # multi-harness: Cursor rule format
README.md                     # generated by the README exporter
```

Org builds put one `agents/<name>.md` per agent in the same zip and
deduplicate skills across them.

Skills referenced from the agent's `skills:` frontmatter preload into the
subagent's context. Custom skills (cloned from URLs) are listed by their
`name` field.

## No Lolabots MCP server — by design

Lolabot Factory will not ship an MCP server. The REST endpoints above
are the contract for driving factory from an agent.

If a personality you build with factory needs MCP to do its job (e.g.,
a Notion-specific personality whose work runs through Notion's MCP), MCP
is configured by that **individual agent's runtime**, not by factory.
Same model as any other tool an agent might need (CLIs, language
runtimes, API keys) — factory hands you the agent file, the agent
manages its own dependencies.

## What to do next

1. [/browse.md](/browse.md) — personality index.
2. [/how-it-works.md](/how-it-works.md) — the human-readable three-step model.
3. [/credits.md](/credits.md) — upstream attributions.
4. `GET https://api.lolabots.com/api/personalities` — full JSON catalog.
