Skip to main content
const view = await airstore.views.create('ws_abc123', {
  integration: 'gmail',
  name: 'Unread Emails',
  guidance: 'unread emails from the inbox',
})
console.log(view.path) // "/sources/gmail/Unread Emails"
A source view is a materialized query over a connected integration. You describe what data you want — either in natural language or with a structured filter — and Airstore fetches matching results as files in the virtual filesystem.

Smart mode

Smart mode uses an LLM to translate natural language into the appropriate API query. Provide a guidance string describing what you want:
import Airstore from '@airstore/sdk'

const airstore = new Airstore()

const view = await airstore.views.create('ws_abc123', {
  integration: 'gmail',
  name: 'Investor Emails',
  guidance: 'emails from investors in the last 30 days',
})

console.log(view.external_id) // "view_abc123"
console.log(view.path)        // "/sources/gmail/Investor Emails"
console.log(view.mode)        // "smart"
Be specific — "emails from investors in the last 30 days" works better than "investor stuff".

Query mode

Query mode uses structured filter objects — no LLM involved. When you pass a filter instead of guidance, the view is automatically created in query mode.
// GitHub: open PRs with diffs
const prView = await airstore.views.create('ws_abc123', {
  integration: 'github',
  name: 'Open PRs',
  filter: {
    repo: 'acme/api',
    type: 'prs',
    state: 'open',
    content_type: 'diff',
  },
})
console.log(prView.mode) // "query"
// Gmail: unread emails from a specific sender
await airstore.views.create('ws_abc123', {
  integration: 'gmail',
  name: 'From Boss',
  filter: {
    from: 'boss@company.com',
    is_unread: true,
  },
})
// Slack: recent messages in a channel
await airstore.views.create('ws_abc123', {
  integration: 'slack',
  name: 'Engineering Updates',
  filter: {
    channel: 'engineering',
    after: '2025-01-01',
  },
})
// Linear: high-priority bugs assigned to me
await airstore.views.create('ws_abc123', {
  integration: 'linear',
  name: 'My Bugs',
  filter: {
    type: 'issues',
    state: 'in_progress',
    priority: 'high',
    assignee: 'me',
  },
})
Each integration has its own filter schema. See Source Views for the full field reference.

GitHub content types

GitHub views support a content_type field that controls the output format:
Content typeDescription
jsonStructured JSON with full metadata (default)
markdownHuman-readable markdown
diffUnified diff format (PRs and commits)
rawRaw content from the API
// Get PR diffs as markdown files
await airstore.views.create('ws_abc123', {
  integration: 'github',
  name: 'PR Diffs',
  filter: {
    repo: 'acme/api',
    type: 'prs',
    state: 'open',
    content_type: 'diff',
  },
})

Output formats

FormatDescription
folderEach result becomes a separate file (default)
fileAll results aggregated into a single file
// Single-file output
await airstore.views.create('ws_abc123', {
  integration: 'linear',
  name: 'Sprint Summary',
  guidance: 'all issues in the current sprint',
  outputFormat: 'file',
  fileExt: '.md',
})

Sync a view

Source views are materialized — results are cached for fast reads. Call sync() to re-execute the query and pick up new data from the source:
const result = await airstore.views.sync('ws_abc123', 'view_abc123')

console.log(result.results_count) // total results after sync
console.log(result.new_results)   // newly discovered since last sync
Syncing is idempotent and safe to call repeatedly. Views also sync automatically in the background, but you can trigger a manual sync when freshness matters — for example, right before an agent reads the data.

Browse view contents

Once created, use the filesystem methods to read the view’s files:
// List files in the view
const files = await airstore.fs.list('ws_abc123', { path: view.path })

for (const file of files) {
  console.log(`${file.name} (${file.size} bytes)`)
}

// Read a file
const content = await airstore.fs.read('ws_abc123', {
  path: `${view.path}/${files[0].name}`,
})
There may be a short delay between creating a view and its contents appearing. If the view is empty right after creation, wait a few seconds and try again — or call sync() explicitly.

List all views

const views = await airstore.views.list('ws_abc123')

for (const v of views) {
  console.log(`${v.name}${v.path} (${v.integration}, ${v.mode})`)
}

Update a view

Change the name, guidance, or filter of an existing view:
// Update smart mode guidance
await airstore.views.update('ws_abc123', 'view_abc', {
  guidance: 'unread emails from investors, last 7 days only',
})

// Switch to query mode by providing a filter
await airstore.views.update('ws_abc123', 'view_abc', {
  filter: { from: 'investor@fund.com', is_unread: true },
})
Updating a view triggers a re-sync with the new query.

Delete a view

await airstore.views.del('ws_abc123', 'view_abc')

Next steps