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

# Create views programmatically

> Use client.views.create in smart and query modes

Use source views to define exactly what data should appear in a workspace filesystem. This is useful in backend provisioning flows where every new workspace should start with the same set of queryable folders.

<Note>
  Before creating a view, the target integration must already be connected in the workspace.
</Note>

## Smart vs query mode

<CodeGroup>
  ```typescript Smart mode (guidance) theme={null}
  import Airstore from '@airstore/sdk'

  const airstore = new Airstore()
  const workspaceId = 'ws_abc123'

  const unreadEmails = await airstore.views.create(workspaceId, {
    integration: 'gmail',
    name: 'Unread Emails',
    guidance: 'Unread inbox emails from the last 7 days',
    outputFormat: 'folder',
  })

  console.log(unreadEmails.path) // /sources/gmail/Unread Emails
  ```

  ```typescript Query mode (filter) theme={null}
  import Airstore from '@airstore/sdk'

  const airstore = new Airstore()
  const workspaceId = 'ws_abc123'

  const fromBoss = await airstore.views.create(workspaceId, {
    integration: 'gmail',
    name: 'From Boss',
    filter: {
      from: 'boss@company.com',
      is_unread: true,
      newer_than: '14d',
    },
    outputFormat: 'folder',
  })

  console.log(fromBoss.mode) // query
  ```
</CodeGroup>

## Idempotent creation pattern

When provisioning runs multiple times, use an "ensure" helper so you update an existing view instead of creating duplicates.

```typescript theme={null}
import Airstore from '@airstore/sdk'

const airstore = new Airstore()

type EnsureViewInput = {
  integration: 'gmail' | 'github'
  name: string
  guidance?: string
  filter?: Record<string, unknown>
  outputFormat?: 'folder' | 'file'
}

async function ensureView(workspaceId: string, desired: EnsureViewInput) {
  const existingViews = await airstore.views.list(workspaceId)
  const existing = existingViews.find(
    (view) => view.integration === desired.integration && view.name === desired.name,
  )

  if (existing) {
    return airstore.views.update(workspaceId, existing.external_id, {
      name: desired.name,
      guidance: desired.guidance,
      filter: desired.filter,
    })
  }

  return airstore.views.create(workspaceId, desired)
}

const workspaceId = 'ws_abc123'

await ensureView(workspaceId, {
  integration: 'gmail',
  name: 'Unread Emails',
  guidance: 'Unread emails from the inbox',
})

await ensureView(workspaceId, {
  integration: 'github',
  name: 'Open PRs',
  filter: {
    repo: 'acme/api',
    type: 'prs',
    state: 'open',
    content_type: 'diff',
  },
})
```

## Integration-specific query examples

<CodeGroup>
  ```typescript Gmail filter theme={null}
  import Airstore from '@airstore/sdk'

  const airstore = new Airstore()

  await airstore.views.create('ws_abc123', {
    integration: 'gmail',
    name: 'Investor Follow-ups',
    filter: {
      from: 'investor@fund.com',
      subject: 'follow up',
      is_unread: true,
      has_attachment: true,
    },
  })
  ```

  ```typescript GitHub filter theme={null}
  import Airstore from '@airstore/sdk'

  const airstore = new Airstore()

  await airstore.views.create('ws_abc123', {
    integration: 'github',
    name: 'Open PR Diffs',
    filter: {
      repo: 'acme/api',
      type: 'prs',
      state: 'open',
      content_type: 'diff',
    },
  })
  ```
</CodeGroup>
