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

# Extension Structure

> File and folder layout of the Pastures Rancher extension.

## Directory Overview

```
pkg/pastures/
├── index.ts              # Plugin entry, routes, CSS, header action
├── product.ts            # Sidebar: virtualType, basicType, weightType
├── package.json          # Extension metadata, Rancher version constraints
├── lib/
│   ├── pasturesApi.ts    # Engine API client, auth, demo mode, safeJson
│   ├── demoResponses.ts  # Synthetic API responses for demo mode
│   └── aiContext.ts      # Page-aware AI suggestions
├── pages/
│   ├── OperationsPage.vue    # Tabbed container (6 tabs)
│   ├── HarvesterPage.vue     # Tabbed container (7 tabs)
│   ├── InfrastructurePage.vue # Tabbed container (3 tabs)
│   ├── AIAgentsPage.vue      # Tabbed container (3 tabs)
│   ├── UpgradeRiskPage.vue   # Embedded in Operations
│   ├── ...                   # 25 more page components
│   └── SettingsPage.vue      # Extension configuration
├── components/
│   ├── PasturesAIDrawer.vue  # Global AI chat drawer
│   ├── ConfirmDialog.vue     # Reusable confirmation modal
│   └── BlastRadiusGraph.vue  # SVG dependency graph
└── nemoclaw/
    └── demoData.ts           # Stub NemoClaw demo data
```

## Key Patterns

### Plugin Entry (`index.ts`)

The `plugin()` function is the extension's entry point. It:

1. Registers all routes (one per page component).
2. Injects global CSS via `injectPasturesCSS()`.
3. Adds a **sparkle button** to the Rancher header that opens the AI drawer.

### Sidebar Registration (`product.ts`)

Rancher extensions use three primitives to define sidebar structure:

| Function        | Purpose                                                     |
| --------------- | ----------------------------------------------------------- |
| `virtualType()` | Declares a sidebar entry pointing to a route                |
| `basicType()`   | Groups entries under a section                              |
| `weightType()`  | Controls display order (higher weight = higher in the list) |

### Tabbed Container Pages

Four pages act as containers for related sub-pages:

<CardGroup cols={2}>
  <Card title="OperationsPage" icon="wrench">
    6 tabs — CIS Benchmarks, Etcd, Monitoring, Audit Log, Upgrade Risk, Backup & DR
  </Card>

  <Card title="HarvesterPage" icon="server">
    7 tabs — VM overview, networks, images, volumes, templates, monitoring, settings
  </Card>

  <Card title="InfrastructurePage" icon="network-wired">
    3 tabs — Nodes, storage, networking
  </Card>

  <Card title="AIAgentsPage" icon="robot">
    3 tabs — Agent list, execution history, configuration
  </Card>
</CardGroup>

Tabbed containers pass an `embedded` prop to child page components to suppress their standalone headers when rendered as a tab.

### API Client (`lib/pasturesApi.ts`)

All communication with the Pastures Engine goes through `engineFetch()`. This wrapper:

* Reads the Engine URL and API key from `localStorage`.
* Attaches the `Authorization: Bearer <key>` header when configured.
* Short-circuits to synthetic responses when `isGlobalDemoMode()` returns `true`.
* Returns responses through `safeJson()` for safe parsing with fallback handling.

### Demo Mode (`lib/demoResponses.ts`)

`getDemoResponse(path)` maps API paths to static response objects. Pages that use inline `fetch` instead of `engineFetch` define their own `DEMO_*` constants and check `isGlobalDemoMode()` in `onMounted`.

### AI Context (`lib/aiContext.ts`)

Maps the current route to a list of suggested questions displayed in the AI drawer. When a user opens the drawer from a specific page, they see contextually relevant prompts.
