Skip to main content
This guide covers what you need to implement when adding a new resource to MIRAGE. Use the Discord or Slack resources as reference.

File Structure

Implementation Steps

1. Config, Accessor, ResourceName

Create a Pydantic config model to hold credentials and an accessor class that wraps it.
Add MY_RESOURCE = "<name>" to the ResourceName enum in mirage/types.py.

2. HTTP Client

Wrap the resource’s API with rate-limit handling. All resources follow the same pattern: async get/post functions with retry on 429.

3. Core VFS

Implement the three VFS operations that map API data to a filesystem:
  • readdir.py — Returns list[str] of child paths for a directory.
  • read.py — Returns bytes content of a file.
  • stat.py — Returns FileStat with name, type, and extras (e.g., IDs).
All three accept (accessor, path, index, prefix) and use IndexCacheStore to cache name-to-ID mappings.

4. Scope Detection and GlobScope Optimization

GlobScope carries the raw path and pattern before expansion. This lets commands decide how to resolve paths efficiently — skipping expensive glob expansion when the resource has a native API for the operation. scope.py parses the unexpanded path to determine the level:
How commands use scope for optimization:
When to use this pattern: When the resource has no search API, keep scope.py as a noop for structural consistency. The file still parses path parts but does not trigger any API calls:

5. Glob Resolution

6. Ops Layer

Thin wrappers that bridge core functions to the command framework:

7. Commands

Copy from an existing resource (Discord/Slack), then:
  1. Replace accessor and core imports.
  2. Set resource="<name>" in decorators.
  3. Add or remove scope-based optimizations depending on API capabilities.
  4. Add resource-specific commands (send message, etc.).

8. Resource Class