Metadata-Version: 2.4
Name: backlot
Version: 0.0.1
Summary: A local emulator for enterprise SaaS APIs, served over your own corpus with per-document ACLs
Author-email: nuri-yoo <yoonuri1@gmail.com>, khj809 <onsealeatang@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/brekkylab/backlot
Project-URL: Repository, https://github.com/brekkylab/backlot
Project-URL: Issues, https://github.com/brekkylab/backlot/issues
Project-URL: Changelog, https://github.com/brekkylab/backlot/releases
Project-URL: Discord, https://discord.gg/XCSsxYH6R
Keywords: mock,rag,slack,gmail,google-drive,jira,confluence,github,notion,s3,amazon-s3,hubspot,linear,graphql,benchmark
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Framework :: FastAPI
Classifier: Topic :: Software Development :: Testing :: Mocking
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastapi>=0.110
Requires-Dist: uvicorn[standard]>=0.29
Requires-Dist: pydantic>=2.6
Requires-Dist: pydantic-settings>=2.2
Requires-Dist: pyyaml>=6.0
Requires-Dist: python-multipart>=0.0.9
Requires-Dist: jsonschema>=4.20
Requires-Dist: typer>=0.27
Requires-Dist: pyjwt[crypto]>=2.8
Requires-Dist: httpx>=0.27
Requires-Dist: graphql-core>=3.2
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-xdist>=3.6; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: httpx2; extra == "dev"
Requires-Dist: ruff~=0.15.22; extra == "dev"
Provides-Extra: examples
Requires-Dist: httpx>=0.27; extra == "examples"
Requires-Dist: slack_sdk>=3.27; extra == "examples"
Requires-Dist: PyGithub>=2.3; extra == "examples"
Requires-Dist: atlassian-python-api>=3.41; extra == "examples"
Requires-Dist: google-api-python-client>=2.120; extra == "examples"
Requires-Dist: google-auth>=2.29; extra == "examples"
Requires-Dist: notion-client>=3.1; extra == "examples"
Requires-Dist: boto3>=1.34; extra == "examples"
Requires-Dist: hubspot-api-client>=12; extra == "examples"
Provides-Extra: mcp
Requires-Dist: mcp>=1.2; extra == "mcp"
Requires-Dist: anthropic[mcp]>=0.40; extra == "mcp"
Requires-Dist: openai>=1.40; extra == "mcp"
Requires-Dist: openai-agents>=0.1; extra == "mcp"
Requires-Dist: pyyaml>=6.0; extra == "mcp"
Requires-Dist: fastmcp>=3; extra == "mcp"
Provides-Extra: llamaindex
Requires-Dist: llama-index-readers-slack>=0.5; extra == "llamaindex"
Requires-Dist: llama-index-readers-google>=0.7; extra == "llamaindex"
Requires-Dist: llama-index-readers-github>=0.11; extra == "llamaindex"
Requires-Dist: llama-index-readers-jira>=0.6; extra == "llamaindex"
Requires-Dist: llama-index-readers-confluence>=0.7; extra == "llamaindex"
Requires-Dist: llama-index-readers-notion>=0.5; extra == "llamaindex"
Requires-Dist: llama-index-readers-s3>=0.6; extra == "llamaindex"
Requires-Dist: llama-index-readers-linear>=0.5; extra == "llamaindex"
Requires-Dist: jira>=3.10; extra == "llamaindex"
Requires-Dist: atlassian-python-api>=4.0; extra == "llamaindex"
Requires-Dist: slack_sdk>=3.43; extra == "llamaindex"
Requires-Dist: google-api-python-client>=2.198; extra == "llamaindex"
Requires-Dist: google-auth>=2.55; extra == "llamaindex"
Requires-Dist: boto3>=1.40; extra == "llamaindex"
Requires-Dist: s3fs>=2026.6; extra == "llamaindex"
Provides-Extra: mirage
Requires-Dist: mirage-ai[fuse]~=0.0.5; extra == "mirage"
Provides-Extra: fsspec
Requires-Dist: fsspec>=2026.6; extra == "fsspec"
Requires-Dist: s3fs>=2026.6; extra == "fsspec"
Requires-Dist: gdrive-fsspec>=0.1; extra == "fsspec"
Requires-Dist: google-api-python-client>=2.198; extra == "fsspec"
Requires-Dist: google-auth>=2.55; extra == "fsspec"
Requires-Dist: pandas>=2.2; extra == "fsspec"
Dynamic: license-file

# Backlot

[![tests](https://github.com/brekkylab/backlot/actions/workflows/ci.yml/badge.svg)](https://github.com/brekkylab/backlot/actions/workflows/ci.yml)
[![python](https://img.shields.io/pypi/pyversions/backlot)](https://pypi.org/project/backlot/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/brekkylab/backlot/blob/main/LICENSE)
[![Discord](https://img.shields.io/badge/Discord-5865F2?logo=discord&logoColor=white)](https://discord.gg/XCSsxYH6R)
[![X](https://img.shields.io/badge/Tweet-000000?logo=x&logoColor=white)](https://x.com/brekkylab)

**Serve your own enterprise playground**

Backlot is a local emulator for enterprise SaaS APIs. Test your Slack, Gmail, Google Drive and the rest of your integrations.

**No account. No token. No network.**

Why would you need that? Because right now:

- **You can't log in yet**. So you create a workspace, register an app, pick OAuth scopes and wait on an admin who has never heard of you. Zero API calls so far.
- **Then you do it again**. Gmail. Jira. Google Drive. Every source starts over from nothing.
- **So you mock it, and the test passes**. It passes because you wrote both sides of it. It always passes.

Backlot is the side you didn't write. It behaves exactly like the real one.

## Quickstart

```bash
pip install backlot
backlot import --bundled   # a corpus ships with the package; nothing to fetch or write
backlot serve              # http://127.0.0.1:8000
```

Or run one programmatically on a free port:

```python
import backlot
from slack_sdk import WebClient                        # pip install slack_sdk

with backlot.serve() as s:                             # no arguments: a tiny hello-world corpus
    slack = WebClient(token=s.token, base_url=f"{s.base_url}/slack/api/")
    print(slack.conversations_list()["channels"])
```

The only change from talking to the live service is the base URL.

## What it serves

Every source on one local port, each behind the path prefix its own SDK expects.

| Service | Base path |
|---|---|
| Slack | `/slack/api` |
| Gmail | `/gmail/v1` |
| Google Drive (Docs, Sheets, Slides) | `/drive/v3` `/docs/v1` `/sheets/v4` `/slides/v1` |
| GitHub | `/github` |
| Jira | `/atlassian/rest/api` |
| Confluence | `/atlassian/wiki/rest/api` |
| Notion | `/notion/v1` |
| Linear | `/linear/graphql` |
| HubSpot | `/hubspot` |
| Fireflies | `/fireflies/graphql` |
| Amazon S3 | `/s3` |

Responses carry the shapes, pagination, auth and per-document ACLs the real ones have, over a corpus you supply. Every user in the corpus gets a token, so you can assert that one caller's documents never reach another.

## Documentation

| | |
|---|---|
| Every source Backlot serves, and every endpoint of each | [supported-sources.md](https://github.com/brekkylab/backlot/blob/main/docs/supported-sources.md) |
| Building a corpus, and public datasets | [corpus.md](https://github.com/brekkylab/backlot/blob/main/docs/corpus.md) |
| Auth schemes and tokens | [auth.md](https://github.com/brekkylab/backlot/blob/main/docs/auth.md) |
| Every `BACKLOT_*` setting | [configuration.md](https://github.com/brekkylab/backlot/blob/main/docs/configuration.md) |

One runnable script per service, driving the vendor's own SDK, plus MCP, LlamaIndex and mirage
walkthroughs: [examples/](https://github.com/brekkylab/backlot/tree/main/examples).

## Trademarks

Backlot is an independent project, **not affiliated with, endorsed by, or sponsored by** any of the
vendors whose APIs it imitates. Slack, Gmail, Google Drive, Google Docs, Google Sheets, Google
Slides, GitHub, Jira, Confluence, Notion, Amazon S3, HubSpot, Linear and Fireflies are trademarks of
their respective owners, named here only to identify the APIs Backlot serves a compatible subset of.
Backlot ships no vendor logo, wordmark or brand asset.

## License

[MIT](https://github.com/brekkylab/backlot/blob/main/LICENSE)
