# How Paperclip Org-Chart Hierarchy Uses `reportsTo` and Role Permissions

> Understand the Paperclip org chart hierarchy using reportsTo and role permissions. Discover how Paperclip manages reporting relationships and fallback authority.

- Repository: [Paperclip/paperclip](https://github.com/paperclipai/paperclip)
- Tags: how-to-guide
- Published: 2026-08-18

---

**Paperclip implements a directed tree structure where `reportsTo` defines manager relationships and role-based permissions resolve fallback authority when reporting chains break.**

The `paperclipai/paperclip` repository models every organization as a hierarchy of **agents**—both human users and AI systems—connected through parent-child relationships. Each agent carries a `reportsTo` field pointing to their manager and a `role` string that determines permission grants in the system.

## Building the Org-Chart Tree

### Agent Definition and `reportsTo`

When creating an agent, the payload accepts `reportsTo` as an optional agent ID. A `null` value designates the agent as a root node—typically the CEO.

```typescript
// ui/src/lib/new-agent-hire-payload.ts
{
  name: "Backend Engineer",
  role: "engineer",
  reportsTo: "mgr-1",   // manager's agent-id; null for root
}

```

The `reportsTo` field is typed as `reportsTo?: string | null` in the creation payload, making the hierarchy relationship explicit at the data layer.

### Computing Agent Order

The UI renders agents in a tree-respecting sequence using `orderAgents()` in [`ui/src/lib/agent-order.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/agent-order.ts). This function walks each agent's `reportsTo` link and positions children directly after their manager (line 123).

```typescript
// ui/src/lib/agent-order.ts
export function orderAgents(agents: Agent[]): Agent[] {
  const byId = new Map(agents.map(a => [a.id, a]));
  return agents.sort((a, b) => {
    const aParent = a.reportsTo && byId.has(a.reportsTo) ? a.reportsTo : null;
    const bParent = b.reportsTo && byId.has(b.reportsTo) ? b.reportsTo : null;
    return aParent === bParent ? 0 : aParent ? -1 : 1;
  });
}

```

### Visualizing the Hierarchy

The `OrgChart` page renders the ordered list with connector lines drawn from each child to their `reportsTo` manager. Status dots indicate runtime state (running, idle, error) using color tokens defined in [`ui/src/index.css`](https://github.com/paperclipai/paperclip/blob/main/ui/src/index.css).

## Role-Based Permission System

### Special Roles with Authority

Not all roles carry permission weight. Paperclip treats three categories distinctly:

- **`ceo` / `cto`** — Top-level roles used for fallback assignments. When a direct manager is missing, the system queries for active agents with these roles.
- **`general`** — Default role for standard agents; no elevated permissions.
- **Free-form roles** — Used for UI grouping, skill-catalog filtering, and display only.

### Server-Side Permission Enforcement

Permission checks query the `agents.role` column directly from the database. In [`server/src/services/recovery/service.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/recovery/service.ts) (lines 1822-1826), the recovery service falls back to CEO/CTO candidates when the reporting chain fails:

```typescript
// server/src/services/recovery/service.ts
if (!candidateIds.length) {
  // Look for any active CTO or CEO if the direct manager is missing
  const roleCandidates = await db
    .where(and(
      eq(agents.companyId, input.run.companyId),
      inArray(agents.role, ["cto", "ceo"])
    ))
    .orderBy(
      sql`case when ${agents.role} = 'cto' then 0 else 1 end`,
      asc(agents.createdAt)
    );
  candidateIds.push(...roleCandidates.map(a => a.id));
}

```

### Human Role Normalization

Human members receive normalized roles through [`server/src/services/company-member-roles.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/company-member-roles.ts). The `grantsForHumanRole` mapping treats `ceo` and `cto` specially, granting them inherited permissions unavailable to other roles.

## Practical Hierarchy Operations

### Task Assignment with Fallback

When Paperclip creates a new task, it attempts assignment in two stages:

1. Assign to the agent's direct manager via `reportsTo`
2. If unavailable, fall back to any active `cto` or `ceo`

This guarantees every task maintains ownership within the reporting line.

### Recovery and Liveness Detection

The recovery service walks the `reportsTo` chain to find a live manager for failing agents. It terminates traversal at `null` (root) or upon cycle detection—implemented in [`server/src/services/recovery/issue-graph-liveness.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/recovery/issue-graph-liveness.ts) (lines 342-345).

### UI Navigation

The Agent detail view ([`ui/src/pages/AgentDetail.tsx`](https://github.com/paperclipai/paperclip/blob/main/ui/src/pages/AgentDetail.tsx), lines 909-910) surfaces hierarchy relationships:

```tsx
// ui/src/pages/AgentDetail.tsx
const reportsToAgent = (allAgents ?? []).find(a => a.id === agent?.reportsTo);

return (
  <>
    {agent.reportsTo && (
      <Link to={agentUrl(reportsToAgent!)} className="hover:underline">
        <Identity name={reportsToAgent!.name} size="sm" />
      </Link>
    )}
  </>
);

```

Direct reports display by filtering where `agent.reportsTo === current.id`.

## Key Source Files

| Purpose | File Path |
|---------|-----------|
| Agent creation payload with `reportsTo` | [`ui/src/lib/new-agent-hire-payload.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/new-agent-hire-payload.ts) |
| Tree-aware ordering algorithm | [`ui/src/lib/agent-order.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/agent-order.ts) |
| Manager link and reporting display | [`ui/src/pages/AgentDetail.tsx`](https://github.com/paperclipai/paperclip/blob/main/ui/src/pages/AgentDetail.tsx) |
| Visual org-chart page | [`ui/src/pages/OrgChart.tsx`](https://github.com/paperclipai/paperclip/blob/main/ui/src/pages/OrgChart.tsx) |
| Recovery service with role fallback | [`server/src/services/recovery/service.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/recovery/service.ts) |
| Cycle detection and liveness | [`server/src/services/recovery/issue-graph-liveness.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/recovery/issue-graph-liveness.ts) |
| Human role permission mapping | [`server/src/services/company-member-roles.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/company-member-roles.ts) |
| Public `reportsTo` API documentation | [`skills/paperclip/references/api-reference.md`](https://github.com/paperclipai/paperclip/blob/main/skills/paperclip/references/api-reference.md) |

## Summary

- **`reportsTo`** stores the manager's agent-id, forming a directed tree with `null` indicating root nodes
- **Agent ordering** in [`ui/src/lib/agent-order.ts`](https://github.com/paperclipai/paperclip/blob/main/ui/src/lib/agent-order.ts) computes visual hierarchy by walking `reportsTo` links
- **`ceo` and `cto` roles** receive special treatment as fallback authorities when reporting chains break
- **Server-side enforcement** queries `agents.role` directly, with explicit handling in recovery and permission services
- **Cycle detection** prevents infinite traversal when walking the hierarchy

## Frequently Asked Questions

### What happens if an agent's `reportsTo` manager is deleted?

Paperclip falls back to any active agent with role `cto` or `ceo`, ordered by role priority (CTO first) then creation date. This ensures operations like task assignment always have a valid owner.

### Can an agent report to multiple managers?

No. The `reportsTo` field accepts a single string ID or `null`. The data model enforces a strict tree structure without multiple parents.

### How does Paperclip prevent circular reporting relationships?

The recovery service in [`server/src/services/recovery/issue-graph-liveness.ts`](https://github.com/paperclipai/paperclip/blob/main/server/src/services/recovery/issue-graph-liveness.ts) detects cycles during traversal. It tracks visited agent IDs and terminates if it encounters a previously seen node.

### Where is the `reportsTo` field documented in the API?

The public API reference at [`skills/paperclip/references/api-reference.md`](https://github.com/paperclipai/paperclip/blob/main/skills/paperclip/references/api-reference.md) documents the `reportsTo` property, confirming it as an optional string accepting agent identifiers or null for root-level agents.