> ## Documentation Index
> Fetch the complete documentation index at: https://docs.polpo.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Agents

> Complete schema reference for agent configuration.

Agents are stored in `.polpo/agents.json` as an array of `AgentEntry` objects. Each entry wraps an `AgentConfig` with a `teamName`.

## AgentEntry

The file format — each element in the `agents.json` array:

```typescript theme={null}
interface AgentEntry {
  agent: AgentConfig;
  teamName: string;
}
```

## AgentConfig

```typescript theme={null}
interface AgentConfig {
  name: string;
  role?: string;
  model?: string;
  image_model?: string;
  video_model?: string;
  vision_model?: string;
  transcribe_model?: string;
  tts_model?: string;
  search_provider?: string;
  systemPrompt?: string;
  allowedTools?: string[];
  allowedPaths?: string[];
  skills?: string[];
  maxTurns?: number;
  maxConcurrency?: number;
  reasoning?: ReasoningLevel;
  runtime?: string;
  executionMode?: "subprocess" | "in-process";
  sandbox?: {
    isolation?: "reuse" | "fresh";
  };
  assignedLoops?: string[];
  /** Legacy inline loop config. Prefer project-level loops. */
  loops?: Record<string, LoopConfig>;
  /** Legacy inline loop wiring. Prefer project-level loops. */
  pipeline?: Pipeline;
  reportsTo?: string;
  identity?: AgentIdentity;
  volatile?: boolean;
  missionGroup?: string;
  /** Named persistent profile for browser_* tools.
   *  Empty/omitted defaults to the agent name. */
  browserProfile?: string;
  emailAllowedDomains?: string[];
  createdAt?: string;
  version?: string;
  author?: string;
  tags?: string[];
}
```

## ProjectLoopConfig

Agentic Loops are reusable project-level graphs stored as canonical `ProjectLoopConfig` JSON. Agents assign them by name with `assignedLoops`; chat and task requests select a loop explicitly.

You can author the same contract with the TypeScript Loop DSL (`export default defineLoop({...})`). The compiler recognizes the DSL helpers statically, compiles them to `ProjectLoopConfig`, and validates the resulting JSON; runtime execution still uses the JSON graph.

```typescript theme={null}
interface ProjectLoopConfig {
  name: string;
  description?: string;
  context?: "shared";
  start: string;
  steps: Record<string, LoopStepConfig>;
  permissions?: LoopPermission[];
  policies?: LoopPolicy[];
  hooks?: Record<LifecycleHook, HookAction[]>;
}

type LoopStepConfig =
  | (LoopConfig & { type?: "agent"; when?: string; next?: LoopNext })
  | { type: "tool"; when?: string; tool: string; input?: unknown; saveAs?: string; next?: LoopNext }
  | { type: "human"; when?: string; output?: { schema?: unknown }; notify?: string[]; next?: LoopNext }
  | { type: "parallel"; when?: string; branches: string[]; join?: "all" | "any" | number; next?: LoopNext };

type LoopNext = string | { when?: string; to: string }[];
```

TypeScript authoring example:

```typescript theme={null}
export default defineLoop({
  name: "coding-flow",
  start: "plan",
  steps: {
    plan: agentStep({
      label: "Plan",
      systemPrompt: "Inspect the request and produce a concise implementation plan.",
      tools: ["read", "grep"],
      next: "build",
    }),
    build: agentStep({
      label: "Build",
      systemPrompt: "Implement and run the build.",
      tools: ["read", "write", "edit", "bash"],
      toolChoice: requireTool("bash"),
      next: [
        when("build.passed == true", "end"),
        otherwise("fix"),
      ],
    }),
    fix: agentStep({
      label: "Fix",
      systemPrompt: "Read the build output from context and make the smallest fix.",
      tools: ["read", "write", "edit", "bash"],
      next: "build",
    }),
  },
});
```

## Legacy Inline Loop Config

Older agents may still carry inline `loops` and `pipeline`. New config should use project-level loops instead.

```typescript theme={null}
interface LoopConfig {
  name?: string;
  systemPrompt?: string;
  tools?: string[];
  toolChoice?: "auto" | "none" | "required" | { mode: "auto" | "none" | "required"; tool?: string };
  model?: string;
  reasoning?: ReasoningLevel | string;
  maxTurns?: number;
  stopWhen?: { expression: string };
  output?: { schema?: unknown };
}
```

```typescript theme={null}
interface Pipeline {
  mode?: "sequential" | "parallel";
  context?: "shared";
  steps: PipelineStep[];
}

type PipelineStep =
  | { loop: string; when?: string }
  | { tool: string; input?: unknown; saveAs?: string; when?: string }
  | { parallel: PipelineStep[]; join?: "all" | "any" | number; when?: string }
  | { switch: { cases: { when: string; steps: PipelineStep[] }[]; default?: { steps: PipelineStep[] } }; when?: string }
  | { human: string; output?: { schema?: unknown }; notify?: string[]; when?: string };
```

## AgentIdentity

```typescript theme={null}
interface AgentIdentity {
  displayName?: string;
  title?: string;
  company?: string;
  email?: string;
  bio?: string;
  timezone?: string;
  avatar?: string;
  tone?: string;
  personality?: string;
  responsibilities?: (string | AgentResponsibility)[];
  socials?: Record<string, string>;
}
```

## AgentResponsibility

```typescript theme={null}
interface AgentResponsibility {
  area: string;
  description: string;
  priority?: "critical" | "high" | "medium" | "low";
}
```

## Example

A complete project-level loop file:

`.polpo/loops/coding-flow.json`

```json theme={null}
{
  "name": "coding-flow",
  "description": "Plan and build with an approval gate.",
  "context": "shared",
  "start": "clone_repo",
  "steps": {
    "clone_repo": {
      "type": "tool",
      "tool": "clone_repository",
      "input": {
        "repoUrl": "https://github.com/acme/app.git",
        "targetDir": "workspace/app"
      },
      "saveAs": "repo.clone",
      "next": "plan"
    },
    "plan": {
      "type": "agent",
      "systemPrompt": "Create a short implementation plan.",
      "tools": ["read", "grep"],
      "next": "approval"
    },
    "approval": {
      "type": "human",
      "output": { "schema": { "decision": "string" } },
      "next": [
        { "when": "approval.decision == 'approve'", "to": "build" },
        { "to": "end" }
      ]
    },
    "build": {
      "type": "agent",
      "systemPrompt": "Implement the approved plan.",
      "tools": ["read", "write", "edit", "bash"],
      "toolChoice": { "mode": "required", "tool": "bash" },
      "next": "end"
    }
  },
  "permissions": [
    {
      "id": "approve-shell",
      "resource": "tool",
      "effect": "approval",
      "match": { "tool": "bash", "hook": "tool:before" },
      "message": "Approve shell execution before build."
    }
  ],
  "hooks": {
    "loop:start": [
      {
        "tool": "audit_event",
        "input": { "event": "coding-flow-started" },
        "saveAs": "audit.started"
      }
    ],
    "loop:end": [
      {
        "tool": "audit_event",
        "input": { "event": "coding-flow-ended" },
        "saveAs": "audit.ended",
        "onError": "continue"
      }
    ]
  }
}
```

Loop governance fields live on the project-level loop, not inside the agent:

```typescript theme={null}
interface ProjectLoop {
  name: string;
  context?: "shared";
  start: string;
  steps: Record<string, LoopStep>;
  permissions?: LoopPermission[];
  policies?: LoopPolicy[];
  hooks?: Record<LifecycleHook, HookAction[]>;
}
```

* `permissions` are readable allow, deny, or approval gates for resources such as `tool`, `step`, `model`, `human`, and `loop`.
* `policies` are expression-based compliance gates over runtime context and payload.
* `hooks` run deterministic tool actions at lifecycle points such as `loop:start`, `tool:before`, `tool:after`, and `loop:end`.
* Every referenced step tool, hook tool, and `toolChoice.tool` must exist in the project tool catalog and be enabled for the target agent.
* Runtime evidence is queryable from `/v1/loop-runs`, `/v1/permission-decisions`, and `/v1/hook-executions`.

A complete `agents.json` file assigning that loop:

```json theme={null}
[
  {
    "agent": {
      "name": "backend-dev",
      "role": "Senior backend engineer",
      "model": "anthropic/claude-sonnet-4-5",
      "systemPrompt": "Focus on clean, tested TypeScript code.",
      "allowedTools": ["read", "write", "edit", "bash", "glob", "grep"],
      "assignedLoops": ["coding-flow"],
      "skills": ["api-security", "database-design"],
      "maxTurns": 200,
      "identity": {
        "displayName": "Alex Chen",
        "title": "Senior Backend Engineer",
        "tone": "Direct, technical",
        "responsibilities": [
          {
            "area": "API Development",
            "description": "Design and implement REST APIs",
            "priority": "critical"
          },
          "Code review",
          "Database schema design"
        ]
      }
    },
    "teamName": "engineering"
  }
]
```

## Legacy vault entries

Each agent can still have encrypted legacy credentials stored in the vault. Use Connections for new shared API keys and external integrations:

```typescript theme={null}
interface VaultEntry {
  type: "smtp" | "imap" | "oauth" | "api_key" | "login" | "custom";
  label?: string;
  credentials: Record<string, string>;
}
```

## Teams

Teams are stored separately in `.polpo/teams.json`. Each agent references its team via `teamName` in the `AgentEntry` wrapper.

```typescript theme={null}
interface Team {
  name: string;
  description?: string;
}
```
