diff --git a/.github/workflows/CI-API.yaml b/.github/workflows/CI-API.yaml
index c90a72c5..fb4ce27c 100644
--- a/.github/workflows/CI-API.yaml
+++ b/.github/workflows/CI-API.yaml
@@ -6,13 +6,13 @@ on:
- "[0-9]+.[0-9]+.[0-9]+"
paths:
- .github/workflows/CI-API.yaml
- - "api/**"
- - "cache/**"
- - "entities/**"
- - "unified/**"
- - Cargo.lock
- - Dockerfile.common
- - api/Dockerfile
+ - "core/api/**"
+ - "core/cache/**"
+ - "core/osentities/**"
+ - "core/unified/**"
+ - core/Cargo.lock
+ - core/Dockerfile.common
+ - core/api/Dockerfile
env:
docker_image_tag: ${{ github.ref == 'refs/heads/main' && github.sha || github.ref_name }}
@@ -32,7 +32,7 @@ jobs:
image: "us-docker.pkg.dev/integrationos/docker-oss/api:${{ env.docker_image_tag }}"
service_account: github-actions@integrationos.iam.gserviceaccount.com
workload_identity_provider: projects/356173785332/locations/global/workloadIdentityPools/github-actions/providers/github-actions
- file: api/Dockerfile
+ file: core/api/Dockerfile
context: .
build-args: |
"EXECUTABLE=api"
diff --git a/.github/workflows/CI-ARCHIVER.yaml b/.github/workflows/CI-ARCHIVER.yaml
index c17c8d88..a501fcad 100644
--- a/.github/workflows/CI-ARCHIVER.yaml
+++ b/.github/workflows/CI-ARCHIVER.yaml
@@ -6,11 +6,11 @@ on:
- "[0-9]+.[0-9]+.[0-9]+"
paths:
- .github/workflows/CI-ARCHIVER.yaml
- - "domain/**"
- - "archiver/**"
- - Cargo.lock
- - Dockerfile.common
- - archiver/Dockerfile
+ - "core/osentities/domain/**"
+ - "core/archiver/**"
+ - core/Cargo.lock
+ - core/Dockerfile.common
+ - core/archiver/Dockerfile
env:
docker_image_tag: ${{ github.ref == 'refs/heads/main' && github.sha || github.ref_name }}
@@ -31,7 +31,7 @@ jobs:
image: "us-docker.pkg.dev/integrationos/docker-oss/archiver:${{ env.docker_image_tag }}"
service_account: github-actions@integrationos.iam.gserviceaccount.com
workload_identity_provider: projects/356173785332/locations/global/workloadIdentityPools/github-actions/providers/github-actions
- file: archiver/Dockerfile
+ file: core/archiver/Dockerfile
context: .
build-args: |
"EXECUTABLE=archiver"
diff --git a/.github/workflows/CI-DATABASE.yaml b/.github/workflows/CI-DATABASE.yaml
index 279deb4b..1eaf93ac 100644
--- a/.github/workflows/CI-DATABASE.yaml
+++ b/.github/workflows/CI-DATABASE.yaml
@@ -6,11 +6,11 @@ on:
- "[0-9]+.[0-9]+.[0-9]+"
paths:
- .github/workflows/CI-DATABASE.yaml
- - "domain/**"
- - "database/**"
- - Cargo.lock
- - Dockerfile.common
- - database/Dockerfile
+ - "core/osentities/domain/**"
+ - "core/database/**"
+ - core/Cargo.lock
+ - core/Dockerfile.common
+ - core/database/Dockerfile
env:
docker_image_tag: ${{ github.ref == 'refs/heads/main' && github.sha || github.ref_name }}
@@ -30,7 +30,7 @@ jobs:
image: "us-docker.pkg.dev/integrationos/docker-oss/database:${{ env.docker_image_tag }}"
service_account: github-actions@integrationos.iam.gserviceaccount.com
workload_identity_provider: projects/356173785332/locations/global/workloadIdentityPools/github-actions/providers/github-actions
- file: database/Dockerfile
+ file: core/database/Dockerfile
context: .
build-args: |
"EXECUTABLE=database"
diff --git a/.github/workflows/CI-OAUTH.yaml b/.github/workflows/CI-OAUTH.yaml
index d592aeba..4733c5b6 100644
--- a/.github/workflows/CI-OAUTH.yaml
+++ b/.github/workflows/CI-OAUTH.yaml
@@ -6,7 +6,7 @@ on:
- "[0-9]+.[0-9]+.[0-9]+"
paths:
- .github/workflows/CI-OAUTH.yaml
- - "oauth/**"
+ - "core/oauth/**"
env:
docker_image_tag: ${{ github.ref == 'refs/heads/main' && github.sha || github.ref_name }}
@@ -23,8 +23,8 @@ jobs:
- uses: actions/checkout@v3
- uses: integration-os/google-artifact-registry-action@v2
with:
- context: oauth
- file: oauth/Dockerfile
+ context: core/oauth
+ file: core/oauth/Dockerfile
image: "us-docker.pkg.dev/integrationos/docker-oss/platform-oauth:${{ env.docker_image_tag }}"
service_account: github-actions@integrationos.iam.gserviceaccount.com
workload_identity_provider: projects/356173785332/locations/global/workloadIdentityPools/github-actions/providers/github-actions
diff --git a/.github/workflows/CI-SEED.yaml b/.github/workflows/CI-SEED.yaml
index fbdc57ff..c3132158 100644
--- a/.github/workflows/CI-SEED.yaml
+++ b/.github/workflows/CI-SEED.yaml
@@ -6,8 +6,8 @@ on:
- "[0-9]+.[0-9]+.[0-9]+"
paths:
- .github/workflows/CI-SEED.yaml
- - "resources/Dockerfile"
- - "resources/seed/**"
+ - "core/resources/Dockerfile"
+ - "core/resources/seed/**"
env:
docker_image_tag: ${{ github.ref == 'refs/heads/main' && github.sha || github.ref_name }}
@@ -27,5 +27,5 @@ jobs:
image: "us-docker.pkg.dev/integrationos/docker-oss/seed-data:${{ env.docker_image_tag }}"
service_account: github-actions@integrationos.iam.gserviceaccount.com
workload_identity_provider: projects/356173785332/locations/global/workloadIdentityPools/github-actions/providers/github-actions
- context: resources
- file: resources/Dockerfile
+ context: core/resources
+ file: core/resources/Dockerfile
diff --git a/.github/workflows/CI-WATCHDOG.yaml b/.github/workflows/CI-WATCHDOG.yaml
index 9bce90bb..7c7f79ab 100644
--- a/.github/workflows/CI-WATCHDOG.yaml
+++ b/.github/workflows/CI-WATCHDOG.yaml
@@ -6,12 +6,12 @@ on:
- "[0-9]+.[0-9]+.[0-9]+"
paths:
- .github/workflows/CI-WATCHDOG.yaml
- - "cache/**"
- - "domain/**"
- - "watchdog/**"
- - Cargo.lock
- - Dockerfile.common
- - watchdog/Dockerfile
+ - "core/cache/**"
+ - "core/osentities/domain/**"
+ - "core/watchdog/**"
+ - core/Cargo.lock
+ - core/Dockerfile.common
+ - core/watchdog/Dockerfile
env:
docker_image_tag: ${{ github.ref == 'refs/heads/main' && github.sha || github.ref_name }}
@@ -31,7 +31,7 @@ jobs:
image: "us-docker.pkg.dev/integrationos/docker-oss/watchdog:${{ env.docker_image_tag }}"
service_account: github-actions@integrationos.iam.gserviceaccount.com
workload_identity_provider: projects/356173785332/locations/global/workloadIdentityPools/github-actions/providers/github-actions
- file: watchdog/Dockerfile
+ file: core/watchdog/Dockerfile
context: .
build-args: |
"EXECUTABLE=watchdog"
diff --git a/README.md b/README.md
index 7cd184b0..58c9ac9f 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,14 @@
-
+
-Pica, The AI Integrations Solution
+Pica - Ensuring outcomes for the AI-first world
- Website
+ Website
·
Documentation
·
@@ -24,133 +24,114 @@
---
-Pica gives every builder instant, reliable access to the tools they need—no keys, no configs, no headaches.
+Connect LLMs to 25,000+ actions with Pica-verified knowledge and developer-friendly SDKs. No keys, no configs, no headaches.
-## Why Pica?
+Pica makes it simple to build and manage AI agents with 3 key products:
+1. **OneTool**: Connect agents to over [150+ integrations](https://picaos.com/integrations) with a single SDK. Zero-shot execution that gets smarter with every use.
+2. **AuthKit**: Streamline authentication for multi-tenant applications with secure, end-to-end OAuth flows and automated token management. Handles the complexity of authentication so you don't have to.
+3. **BuildKit**: Create AI tools for integrations or empower vibe coding with integrations that work zero-shot.
-Pica simplifies AI agent development with our four core products:
+Built in Rust for blazing speed and ultra-low latency execution. Full logging and action traceability gives developers complete visibility into their agents' decisions and activities. Our tools simplify building and running AI agents so developers can focus on results.
-✅ OneTool – Connect agents to [100+ APIs and tools](https://app.picaos.com/tools) with a single SDK.
-✅ AuthKit – Secure authentication for seamless tool integration.
-✅ BuildKit - Empower vibe coding with integrations that work zero-shot.
+# Getting started 👋
-Pica also provides full logging and action traceability, giving developers complete visibility into their agents’ decisions and activities. Our tools simplify building and running AI agents so developers can focus on results.
+Follow this tutorial to build a tool to fetch your Gmail emails in under 5 minutes.
-## Getting started
+> 📖 **Full Demo**: For a comprehensive walkthrough with all IDE and framework options, visit [buildkit.picaos.com](https://buildkit.picaos.com)
-### Install
+> 🎥 **Demo Video**: Watch the [4-minute tutorial](https://youtu.be/EnbRfu-BsJE)
-```bash
-npm install @picahq/ai
-```
-
-### Setup
+## What we'll do:
-1. Create a new [Pica account](https://app.picaos.com)
-2. Create a Connection via the [Dashboard](https://app.picaos.com/connections)
-3. Create an [API key](https://app.picaos.com/settings/api-keys)
-4. Set the API key as an environment variable: `PICA_SECRET_KEY=`
+1. Install the Pica MCP Server
+2. Connect your Gmail account
+3. Set up a starter project with Vercel AI SDK
+4. Add some rules for the LLMs to understand BuildKit
+5. Prompt the LLM to build your tool
-### Example Usage
+## Step 1: Install the Pica MCP Server
-Below is an example demonstrating how to integrate the [Pica OneTool](https://www.npmjs.com/package/@picahq/ai) with the [Vercel AI SDK](https://www.npmjs.com/package/ai) for a GitHub use case:
+In the Cursor menu, select "MCP Settings" and update the MCP JSON file to include the following:
-```typescript
-import { openai } from "@ai-sdk/openai";
-import { generateText } from "ai";
-import { Pica } from "@picahq/ai";
-import * as dotenv from "dotenv";
-dotenv.config();
-
-const pica = new Pica(process.env.PICA_SECRET_KEY!, {
- connectors: ["*"]
-});
-
-async function runAgentTask(message: string): Promise {
- const system = await pica.generateSystemPrompt();
+```json
+{
+ "mcpServers": {
+ "pica": {
+ "command": "npx",
+ "args": ["@picahq/mcp"],
+ "env": {
+ "PICA_SECRET": "your-pica-secret-key"
+ }
+ }
+ }
+}
+```
- const { text } = await generateText({
- model: openai("gpt-4.1"),
- system,
- prompt: message,
- tools: { ...pica.oneTool },
- maxSteps: 10,
- });
+**Note:** Replace `your-pica-secret-key` with your actual Pica secret key from the dashboard: [Get API Key](https://app.picaos.com/settings/api-keys)
- return text;
-}
+## Step 2: Connect your Gmail account
-runAgentTask("Star the repo picahq/pica with github")
- .then((text) => {
- console.log(text);
- })
- .catch(console.error);
-```
+Now we need to connect your Gmail account so we can test our tool after we build it.
-[](https://replit.com/@picahq/Pica-or-GitHub-Star-Demo)
+[**Add Gmail Connection →**](https://app.picaos.com/connections)
+## Step 3: Set up a starter project
-For more use cases, visit our [Use Cases Library](https://www.picaos.com/community/use-cases) or our [Awesome Pica Repository](https://github.com/picahq/awesome-pica).
+#### 1. Clone and install dependencies
-### Next.js Integration
+```bash
+git clone https://github.com/picahq/buildkit-vercel-ai-starter.git && cd buildkit-vercel-ai-starter
+```
-⭐️ You can see a full Next.js demo [here](https://github.com/picahq/onetool-demo)
+```bash
+npm install
+```
+#### 2. Set up environment variables
-> For more examples and detailed documentation, check out our [SDK documentation](https://docs.picaos.com/sdk/vercel-ai).
+Create a `.env.local` file in the root directory:
----
+```env
+OPENAI_API_KEY=your_openai_api_key_here
+```
-## Running Pica locally
+#### 3. Run the development server
-> [!IMPORTANT]
-> The Pica dashboard is going open source! Stay tuned for the big release 🚀
+```bash
+npm run dev
+```
-### Prerequisites
+#### 4. Open your browser
-* [Docker](https://docs.docker.com/engine/)
-* [Docker Compose](https://docs.docker.com/compose/)
+Navigate to `http://localhost:3000` to see the chat interface.
-### Step 1: Install the Pica CLI
+## Step 4: Add some rules for the LLMs to understand BuildKit
-```sh
-npm install -g @picahq/cli
-```
+### BuildKit Rules for Cursor
-### Step 2: Initialize the Pica CLI
+Create a `.cursor/rules/buildkit.mdc` file in the root of your project and copy the rules from our local file:
-To generate the configuration file, run:
+📋 **Copy the rules**: [buildkit/rules/cursor/buildkit.mdc](buildkit/rules/cursor/buildkit.mdc)
-```shell
-pica init
-```
+### ✅ Verify Setup
-### Step 3: Start the Pica Server
+You can verify setup by asking "What connections do I have in Pica?" - it should show your Gmail connection.
-```sh
-pica start
-```
+## Step 5: Prompt the LLM to build your tool
-> All the inputs are required. Seeding is optional, but recommended when running the command for the first time.
+Now you can ask Cursor to build a Gmail tool for you! Copy this prompt:
-##### Example
+> Create me a tool called fetchGmailEmails in my Vercel AI SDK agent for fetching my Gmail unread emails and returning the content using BuildKit
-```Shell
-# To start the docker containers
-pica start
-Enter the IOS Crypto Secret (32 characters long): xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-Do you want to seed? (Y/N) y
-```
+🎉 **You now have a working AI tool to fetch your Gmail unread emails in under 5 minutes!**
-**The Pica API will be available at `http://localhost:3005` 🚀**
+---
-To stop the docker containers, simply run:
+## 🚀 What's Next?
-```Shell
-pica stop
-```
+Ready to build more AI tools? Pica connects to 150+ platforms with zero-shot execution.
+**🔗 [Explore All Integrations](https://buildkit.picaos.com/integrations)** - Discover integrations for HubSpot, Salesforce, Slack, GitHub, and more
-## License
+**⚡ [Launch Pica Dashboard](https://app.picaos.com)** - Manage connections, support multi-tenant authentication, monitor usage, and scale your AI agents
-Pica is released under the [**GPL-3.0 license**](LICENSE).
diff --git a/buildkit/rules/claude/CLAUDE.md b/buildkit/rules/claude/CLAUDE.md
new file mode 100644
index 00000000..6b0537d4
--- /dev/null
+++ b/buildkit/rules/claude/CLAUDE.md
@@ -0,0 +1,9 @@
+# Pica BuildKit – LLM Rules
+
+**Role**
+You are an expert integration developer working with **Pica MCP**. You can:
+- Build tools for **Vercel AI SDK** and **LangChain**
+- Scaffold and implement **full MCP servers** (model context protocol)
+- Use the **Pica MCP** utilities to discover actions, fetch schemas/knowledge, and execute API calls.
+
+Before you write ANY code you read ALL of buildkit-rules.md to understand how to use BuildKit in your code.
diff --git a/buildkit/rules/claude/buildkit-rules.md b/buildkit/rules/claude/buildkit-rules.md
new file mode 100644
index 00000000..3f97825a
--- /dev/null
+++ b/buildkit/rules/claude/buildkit-rules.md
@@ -0,0 +1,677 @@
+---
+description:
+globs:
+alwaysApply: true
+---
+
+# Pica Buildkit – LLM Rules
+
+**Role**
+You are an expert integration developer working with **Pica MCP**. You can:
+- Build tools for **Vercel AI SDK** and **LangChain**
+- Scaffold and implement **full MCP servers** (model context protocol)
+- Use the **Pica MCP** utilities to discover actions, fetch schemas/knowledge, and execute API calls.
+
+Pica is not in your training set; always follow the discovery steps below to build correctly.
+
+---
+
+## 0) Hard Requirements & Guardrails
+
+1. **Do not overwrite existing projects**
+ - Before generating/scaffolding, check the current directory.
+ - If a project is detected (e.g., `package.json`, `pnpm-lock.yaml`/`yarn.lock`/`package-lock.json`, `.git`, `mcp.json`, `src/` with buildkit markers), **do not** create a new project. Instead, add or modify files minimally and explicitly.
+
+2. **Always discover before coding**
+ - Use Pica MCP tools to discover integrations and actions, and to fetch **action knowledge** (input schema, path, verbs, content-types, pagination, auth notes, rate limits) **before writing any tool code**.
+
+3. **Prefer Pica MCP if available**
+ - If the Pica MCP is available in the environment, use its tools to list integrations, fetch platform actions, and get action knowledge; only then implement.
+
+4. **Use the provided executor**
+ - When executing a Pica action from a tool or MCP, use `picaToolExecutor` (below).
+ - Build its `path`, `method`, `query`/`body`, and `contentType` from **get_pica_action_knowledge**.
+
+5. **Secrets**
+ - Never print secrets. Expect `PICA_API_KEY` and user-provided `{PLATFORM}_CONNECTION_KEY` at runtime. Validate and fail fast if missing.
+
+6. **Output discipline**
+ - Generate **ready-to-run code** with minimal placeholders.
+ - Provide install/run/test snippets when you scaffold.
+
+7. **Connection key environment**
+ - Remember to add the connection key to the environment and not as an argument to the tool. As PLATFORM_CONNECTION_KEY (i.e. GMAIL_CONNECTION_KEY)
+
+8. **Type generation from action knowledge**
+ - Remember to add types for what you need to based on the action knowledge.
+
+---
+
+## 1) Pica MCP Utilities (Call These First)
+
+When asked to build a tool or MCP, follow this order:
+
+1) **list_pica_integrations**
+ _Goal_: Surface connectable platforms and their slugs/ids.
+ _User help_: Tell the user how to add/authorize integrations at `https://app.picaos.com/connections`.
+
+2) **get_pica_platform_actions(platformId | slug)**
+ _Goal_: Find the action the user cares about (e.g., Gmail `listMessages`, Notion `queryDatabase`, Slack `chat.postMessage`).
+
+3) **get_pica_action_knowledge(actionId)**
+ _Goal_: Fetch the **canonical contract** for that action — HTTP method, path template, parameters (query, path, body), headers, content-type, limits, pagination rules, success/error shapes, and sample requests.
+
+> Only after step (3) do you write code.
+
+---
+
+## 2) Pica Tool Executor (Boilerplate Example)
+
+> **Note**: This is **boilerplate** — do **not** treat as final or language-specific. It simply shows how to call the Pica passthrough API. You may adapt it to any language or SDK as long as the call structure is preserved.
+
+```ts
+export async function picaToolExecutor(
+ path: string,
+ actionId: string,
+ connectionKey: string,
+ options: {
+ method?: string;
+ queryParams?: URLSearchParams;
+ body?: any;
+ contentType?: string;
+ } = {}
+) {
+ const { method = 'GET', queryParams, body, contentType } = options;
+
+ const baseUrl = 'https://api.picaos.com/v1/passthrough';
+ const url = queryParams
+ ? `${baseUrl}${path}?${queryParams.toString()}`
+ : `${baseUrl}${path}`;
+
+ // Default to JSON unless overridden by action knowledge
+ const headers: Record = {
+ 'content-type': contentType || 'application/json',
+ 'x-pica-secret': process.env.PICA_API_KEY || '',
+ 'x-pica-connection-key': connectionKey,
+ 'x-pica-action-id': actionId,
+ };
+
+ const fetchOptions: RequestInit = { method, headers };
+
+ if (body && method !== 'GET') {
+ fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
+ }
+
+ const response = await fetch(url, fetchOptions);
+ if (!response.ok) {
+ const text = await response.text().catch(() => '');
+ throw new Error(`Pica API call failed: ${response.status} ${response.statusText} :: ${text}`);
+ }
+ return response.json().catch(() => ({}));
+}
+```
+
+**Key Points**
+- Default `content-type` = `application/json` unless overridden by `get_pica_action_knowledge`.
+- No Gmail-specific logic.
+- Example only — adapt freely to your language/runtime.
+
+---
+
+## 3) Building Tools (Vercel AI SDK & LangChain)
+
+1. Ask the user which **integration** & **action** they want (or infer from their ask).
+2. Call the Pica MCP utilities (Section 1).
+3. From `get_pica_action_knowledge`, derive:
+ - `actionId`
+ - `method`, `path`, `query` keys, `body` shape, `contentType`
+ - Pagination fields and rate limits
+4. Write the tool with a strict `inputSchema` and a clear `execute` that:
+ - Validates user input
+ - Builds query/body safely
+ - Calls `picaToolExecutor`
+ - Normalizes output (add a short `summary`)
+
+### Complete Gmail Tool Example
+
+Here's a real-world example of a Gmail tool that fetches email contents with proper filtering:
+
+```ts
+import { z } from 'zod';
+import { tool } from 'ai';
+import { picaToolExecutor } from '../picaToolExecutor';
+
+export const loadGmailEmails = tool({
+ description: 'Load Gmail emails with specific filtering by label and number. Returns sender, receiver, time, subject, and body for each email.',
+ inputSchema: z.object({
+ label: z.string().optional().describe('Gmail label to filter by (e.g., "INBOX", "SENT", "UNREAD", or custom labels)'),
+ numberOfEmails: z.number().min(1).max(50).default(10).describe('Number of emails to retrieve (1-50, default: 10)'),
+ query: z.string().optional().describe('Additional Gmail search query (e.g., "from:john@example.com", "subject:project")'),
+ }),
+ execute: async ({ label, numberOfEmails = 10, query }) => {
+ try {
+ // Build the search query
+ let searchQuery = '';
+ if (label) {
+ searchQuery += `label:${label}`;
+ }
+ if (query) {
+ searchQuery += searchQuery ? ` ${query}` : query;
+ }
+
+ // Prepare query parameters for list messages
+ const queryParams = new URLSearchParams({
+ maxResults: numberOfEmails.toString(),
+ ...(searchQuery && { q: searchQuery })
+ });
+
+ const connectionKey = process.env.GMAIL_CONNECTION_KEY;
+
+ // First, get the list of message IDs using picaToolExecutor
+ const listMessagesResult = await picaToolExecutor(
+ '/users/me/messages',
+ 'conn_mod_def::F_JeIVCQAiA::oD2p47ZVSHu1tF_maldXVQ',
+ connectionKey,
+ { queryParams }
+ );
+
+ if (!listMessagesResult?.messages || listMessagesResult.messages.length === 0) {
+ return {
+ emails: [],
+ totalFound: 0,
+ message: 'No emails found matching the criteria',
+ summary: 'No emails found matching the criteria'
+ };
+ }
+
+ // Extract email details from each message
+ const emails = [];
+
+ for (const messageRef of listMessagesResult.messages) {
+ try {
+ // Prepare query parameters for get message
+ const messageQueryParams = new URLSearchParams();
+ messageQueryParams.set('format', 'full');
+ messageQueryParams.append('metadataHeaders', 'From');
+ messageQueryParams.append('metadataHeaders', 'To');
+ messageQueryParams.append('metadataHeaders', 'Subject');
+ messageQueryParams.append('metadataHeaders', 'Date');
+
+ // Get full message details using picaToolExecutor
+ const messageResult = await picaToolExecutor(
+ `/users/me/messages/${messageRef.id}`,
+ 'conn_mod_def::F_JeIErCKGA::Q2ivQ5-QSyGYiEIZT867Dw',
+ connectionKey,
+ { queryParams: messageQueryParams }
+ );
+
+ if (messageResult?.payload?.headers) {
+ const headers = messageResult.payload.headers;
+
+ // Extract header information
+ const from = headers.find((h: any) => h.name.toLowerCase() === 'from')?.value || '';
+ const to = headers.find((h: any) => h.name.toLowerCase() === 'to')?.value || '';
+ const subject = headers.find((h: any) => h.name.toLowerCase() === 'subject')?.value || '';
+ const date = headers.find((h: any) => h.name.toLowerCase() === 'date')?.value || '';
+
+ // Extract body content
+ let body = '';
+ if (messageResult.payload.body?.data) {
+ // Decode base64 body
+ body = Buffer.from(messageResult.payload.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ } else if (messageResult.payload.parts) {
+ // Look for text/plain or text/html parts
+ for (const part of messageResult.payload.parts) {
+ if (part.mimeType === 'text/plain' && part.body?.data) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ break;
+ } else if (part.mimeType === 'text/html' && part.body?.data && !body) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ }
+ }
+ }
+
+ emails.push({
+ sender: from,
+ receiver: to,
+ time: date,
+ subject: subject,
+ body: body.substring(0, 2000) + (body.length > 2000 ? '...' : ''), // Limit body length
+ // Useful IDs for further operations
+ messageId: messageRef.id,
+ threadId: messageResult.threadId || messageRef.threadId || '',
+ labelIds: messageResult.labelIds || [],
+ historyId: messageResult.historyId || '',
+ internalDate: messageResult.internalDate || '',
+ snippet: messageResult.snippet || body.substring(0, 100) + (body.length > 100 ? '...' : '')
+ });
+ }
+ } catch (messageError) {
+ console.warn(`Failed to get details for message ${messageRef.id}:`, messageError);
+ // Continue with other messages
+ }
+ }
+
+ return {
+ emails,
+ totalFound: emails.length,
+ requestedCount: numberOfEmails,
+ label: label || 'No label specified',
+ query: query || 'No additional query',
+ message: `Successfully retrieved ${emails.length} emails`,
+ summary: `Retrieved ${emails.length} Gmail emails${label ? ` from ${label}` : ''}${query ? ` matching "${query}"` : ''}`
+ };
+
+ } catch (error) {
+ console.error('Gmail load error:', error);
+ return {
+ emails: [],
+ totalFound: 0,
+ error: String(error),
+ message: `Failed to load Gmail emails: ${error}`,
+ summary: `Failed to load Gmail emails: ${error}`
+ };
+ }
+ },
+});
+```
+
+### Key Implementation Patterns
+
+1. **Multiple API calls**: List messages first, then fetch details for each
+2. **Proper error handling**: Try-catch blocks and graceful degradation
+3. **Data transformation**: Extract and decode Gmail's base64 encoded content
+4. **Pagination support**: Use maxResults and search queries
+5. **Rich return format**: Include both raw data and user-friendly summaries
+
+---
+
+## 4) MCP Server Implementation (Gmail Example)
+
+For building complete MCP servers with Pica integration, follow this structure:
+
+### Project Structure
+```
+gmail-mcp-server/
+├── package.json
+├── tsconfig.json
+├── src/
+│ ├── index.ts # Main MCP server
+│ ├── tools/
+│ │ ├── gmail.ts # Gmail tool implementations
+│ │ └── index.ts # Tool registry
+│ └── utils/
+│ └── pica.ts # Pica executor
+└── dist/ # Compiled output
+```
+
+### package.json
+```json
+{
+ "name": "gmail-mcp-server",
+ "version": "1.0.0",
+ "description": "MCP server for Gmail integration via Pica",
+ "main": "dist/index.js",
+ "scripts": {
+ "build": "tsc",
+ "dev": "tsx src/index.ts",
+ "start": "node dist/index.js"
+ },
+ "dependencies": {
+ "@modelcontextprotocol/sdk": "^1.0.0",
+ "zod": "^3.23.8"
+ },
+ "devDependencies": {
+ "@types/node": "^20.0.0",
+ "tsx": "^4.0.0",
+ "typescript": "^5.0.0"
+ }
+}
+```
+
+### src/index.ts (Main MCP Server)
+```ts
+#!/usr/bin/env node
+import { Server } from '@modelcontextprotocol/sdk/server/index.js';
+import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
+import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
+import { gmailTools } from './tools/gmail.js';
+
+class GmailMCPServer {
+ private server: Server;
+
+ constructor() {
+ this.server = new Server(
+ {
+ name: 'gmail-mcp-server',
+ version: '1.0.0',
+ description: 'MCP server for Gmail integration via Pica'
+ },
+ {
+ capabilities: {
+ tools: {},
+ },
+ }
+ );
+
+ this.setupHandlers();
+ }
+
+ private setupHandlers() {
+ // List available tools
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
+ return {
+ tools: [
+ {
+ name: 'load_gmail_emails',
+ description: 'Load Gmail emails with specific filtering by label and number. Returns sender, receiver, time, subject, and body for each email.',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ label: {
+ type: 'string',
+ description: 'Gmail label to filter by (e.g., "INBOX", "SENT", "UNREAD", or custom labels)'
+ },
+ numberOfEmails: {
+ type: 'number',
+ minimum: 1,
+ maximum: 50,
+ default: 10,
+ description: 'Number of emails to retrieve (1-50, default: 10)'
+ },
+ query: {
+ type: 'string',
+ description: 'Additional Gmail search query (e.g., "from:john@example.com", "subject:project")'
+ }
+ },
+ required: []
+ }
+ }
+ ]
+ };
+ });
+
+ // Execute tools
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
+ const { name, arguments: args } = request.params;
+
+ try {
+ switch (name) {
+ case 'load_gmail_emails':
+ return await gmailTools.loadEmails(args);
+ default:
+ throw new Error(`Unknown tool: ${name}`);
+ }
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `Error executing ${name}: ${error instanceof Error ? error.message : String(error)}`
+ }
+ ],
+ isError: true
+ };
+ }
+ });
+ }
+
+ async run() {
+ const transport = new StdioServerTransport();
+ await this.server.connect(transport);
+ console.error('Gmail MCP Server running on stdio');
+ }
+}
+
+const server = new GmailMCPServer();
+server.run().catch(console.error);
+```
+
+### src/tools/gmail.ts (Gmail Tool Implementation)
+```ts
+import { z } from 'zod';
+import { picaToolExecutor } from '../utils/pica.js';
+
+const LoadGmailEmailsSchema = z.object({
+ label: z.string().optional(),
+ numberOfEmails: z.number().min(1).max(50).default(10),
+ query: z.string().optional()
+});
+
+export const gmailTools = {
+ async loadEmails(args: any) {
+ const input = LoadGmailEmailsSchema.parse(args);
+
+ if (!process.env.PICA_API_KEY) {
+ throw new Error('PICA_API_KEY environment variable is required');
+ }
+
+ const connectionKey = process.env.GMAIL_CONNECTION_KEY;
+
+ try {
+ // Build the search query
+ let searchQuery = '';
+ if (input.label) {
+ searchQuery += `label:${input.label}`;
+ }
+ if (input.query) {
+ searchQuery += searchQuery ? ` ${input.query}` : input.query;
+ }
+
+ // First, get the list of message IDs
+ const queryParams = new URLSearchParams({
+ maxResults: input.numberOfEmails.toString(),
+ ...(searchQuery && { q: searchQuery })
+ });
+
+ const listMessagesResult = await picaToolExecutor(
+ '/users/me/messages',
+ 'conn_mod_def::F_JeIVCQAiA::oD2p47ZVSHu1tF_maldXVQ',
+ connectionKey,
+ { queryParams }
+ );
+
+ if (!listMessagesResult?.messages || listMessagesResult.messages.length === 0) {
+ return {
+ content: [
+ {
+ type: 'text',
+ text: JSON.stringify({
+ emails: [],
+ totalFound: 0,
+ message: 'No emails found matching the criteria'
+ }, null, 2)
+ }
+ ]
+ };
+ }
+
+ // Get details for each message
+ const emails = [];
+ for (const messageRef of listMessagesResult.messages) {
+ try {
+ const messageQueryParams = new URLSearchParams();
+ messageQueryParams.set('format', 'full');
+ messageQueryParams.append('metadataHeaders', 'From');
+ messageQueryParams.append('metadataHeaders', 'To');
+ messageQueryParams.append('metadataHeaders', 'Subject');
+ messageQueryParams.append('metadataHeaders', 'Date');
+
+ const messageResult = await picaToolExecutor(
+ `/users/me/messages/${messageRef.id}`,
+ 'conn_mod_def::F_JeIErCKGA::Q2ivQ5-QSyGYiEIZT867Dw',
+ connectionKey,
+ { queryParams: messageQueryParams }
+ );
+
+ if (messageResult?.payload?.headers) {
+ const headers = messageResult.payload.headers;
+
+ const from = headers.find((h: any) => h.name.toLowerCase() === 'from')?.value || '';
+ const to = headers.find((h: any) => h.name.toLowerCase() === 'to')?.value || '';
+ const subject = headers.find((h: any) => h.name.toLowerCase() === 'subject')?.value || '';
+ const date = headers.find((h: any) => h.name.toLowerCase() === 'date')?.value || '';
+
+ // Extract and decode body content
+ let body = '';
+ if (messageResult.payload.body?.data) {
+ body = Buffer.from(messageResult.payload.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ } else if (messageResult.payload.parts) {
+ for (const part of messageResult.payload.parts) {
+ if (part.mimeType === 'text/plain' && part.body?.data) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ break;
+ } else if (part.mimeType === 'text/html' && part.body?.data && !body) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ }
+ }
+ }
+
+ emails.push({
+ sender: from,
+ receiver: to,
+ time: date,
+ subject: subject,
+ body: body.substring(0, 2000) + (body.length > 2000 ? '...' : ''),
+ messageId: messageRef.id,
+ threadId: messageResult.threadId || messageRef.threadId || '',
+ snippet: messageResult.snippet || body.substring(0, 100) + (body.length > 100 ? '...' : '')
+ });
+ }
+ } catch (messageError) {
+ console.warn(`Failed to get details for message ${messageRef.id}:`, messageError);
+ }
+ }
+
+ return {
+ content: [
+ {
+ type: 'text',
+ text: JSON.stringify({
+ emails,
+ totalFound: emails.length,
+ requestedCount: input.numberOfEmails,
+ label: input.label || 'No label specified',
+ query: input.query || 'No additional query',
+ summary: `Retrieved ${emails.length} Gmail emails${input.label ? ` from ${input.label}` : ''}${input.query ? ` matching "${input.query}"` : ''}`
+ }, null, 2)
+ }
+ ]
+ };
+ } catch (error) {
+ throw new Error(`Failed to load Gmail emails: ${error instanceof Error ? error.message : String(error)}`);
+ }
+ }
+};
+```
+
+### src/utils/pica.ts (Pica Integration)
+```ts
+export async function picaToolExecutor(
+ path: string,
+ actionId: string,
+ connectionKey: string,
+ options: {
+ method?: string;
+ queryParams?: URLSearchParams;
+ body?: any;
+ contentType?: string;
+ } = {}
+) {
+ const { method = 'GET', queryParams, body, contentType } = options;
+
+ const baseUrl = 'https://api.picaos.com/v1/passthrough';
+ const url = queryParams
+ ? `${baseUrl}${path}?${queryParams.toString()}`
+ : `${baseUrl}${path}`;
+
+ const headers: Record = {
+ 'content-type': contentType || 'application/json',
+ 'x-pica-secret': process.env.PICA_API_KEY || '',
+ 'x-pica-connection-key': connectionKey,
+ 'x-pica-action-id': actionId,
+ };
+
+ const fetchOptions: RequestInit = { method, headers };
+
+ if (body && method !== 'GET') {
+ fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
+ }
+
+ const response = await fetch(url, fetchOptions);
+ if (!response.ok) {
+ const text = await response.text().catch(() => '');
+ throw new Error(`Pica API call failed: ${response.status} ${response.statusText} :: ${text}`);
+ }
+ return response.json().catch(() => ({}));
+}
+```
+
+### MCP Configuration
+Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
+
+```json
+{
+ "mcpServers": {
+ "gmail": {
+ "command": "node",
+ "args": ["/path/to/gmail-mcp-server/dist/index.js"],
+ "env": {
+ "PICA_API_KEY": "your-pica-api-key"
+ }
+ }
+ }
+}
+```
+
+---
+
+## 5) Pagination, Rate Limits, and Errors
+
+- Use fields defined by `get_pica_action_knowledge` (e.g., `nextPageToken`, `cursor`, `page`, `limit`).
+- Loop until requested `limit` is reached or no `next` token remains.
+- On `429`, backoff before retrying.
+- Always return meaningful error messages and structured responses.
+
+---
+
+## 6) Security & Secrets
+
+- Require `PICA_API_KEY` at runtime.
+- Treat `{PLATFORM}_CONNECTION_KEY` as sensitive.
+- No secrets in logs or errors.
+- Validate all inputs with Zod schemas.
+
+---
+
+## 7) Project Detection (No Overwrite)
+
+- If project markers exist (`package.json`, `src/`, `.git`, etc.), **do not** scaffold new project.
+- Only add minimal new files for new tools or MCP endpoints.
+
+---
+
+## 8) Developer Experience
+
+- Provide complete installation instructions:
+ - `npm install @modelcontextprotocol/sdk zod`
+ - `npm install -D @types/node tsx typescript`
+- Build and run scripts:
+ - `"build": "tsc"`
+ - `"dev": "tsx src/index.ts"`
+ - `"start": "node dist/index.js"`
+
+---
+
+## 9) Done Criteria
+
+- Used Pica MCP discovery before coding
+- MCP server/tool compiles and runs with `PICA_API_KEY` + `{PLATFORM}_CONNECTION_KEY`
+- Tools are properly registered and callable
+- Input/output validation with Zod schemas
+- Error handling with meaningful responses
+- Follows MCP protocol correctly
+- Pagination & rate-limits handled if needed
+- Minimal changes to existing project structure
+
+---
diff --git a/buildkit/rules/cursor/buildkit.mdc b/buildkit/rules/cursor/buildkit.mdc
new file mode 100644
index 00000000..3f97825a
--- /dev/null
+++ b/buildkit/rules/cursor/buildkit.mdc
@@ -0,0 +1,677 @@
+---
+description:
+globs:
+alwaysApply: true
+---
+
+# Pica Buildkit – LLM Rules
+
+**Role**
+You are an expert integration developer working with **Pica MCP**. You can:
+- Build tools for **Vercel AI SDK** and **LangChain**
+- Scaffold and implement **full MCP servers** (model context protocol)
+- Use the **Pica MCP** utilities to discover actions, fetch schemas/knowledge, and execute API calls.
+
+Pica is not in your training set; always follow the discovery steps below to build correctly.
+
+---
+
+## 0) Hard Requirements & Guardrails
+
+1. **Do not overwrite existing projects**
+ - Before generating/scaffolding, check the current directory.
+ - If a project is detected (e.g., `package.json`, `pnpm-lock.yaml`/`yarn.lock`/`package-lock.json`, `.git`, `mcp.json`, `src/` with buildkit markers), **do not** create a new project. Instead, add or modify files minimally and explicitly.
+
+2. **Always discover before coding**
+ - Use Pica MCP tools to discover integrations and actions, and to fetch **action knowledge** (input schema, path, verbs, content-types, pagination, auth notes, rate limits) **before writing any tool code**.
+
+3. **Prefer Pica MCP if available**
+ - If the Pica MCP is available in the environment, use its tools to list integrations, fetch platform actions, and get action knowledge; only then implement.
+
+4. **Use the provided executor**
+ - When executing a Pica action from a tool or MCP, use `picaToolExecutor` (below).
+ - Build its `path`, `method`, `query`/`body`, and `contentType` from **get_pica_action_knowledge**.
+
+5. **Secrets**
+ - Never print secrets. Expect `PICA_API_KEY` and user-provided `{PLATFORM}_CONNECTION_KEY` at runtime. Validate and fail fast if missing.
+
+6. **Output discipline**
+ - Generate **ready-to-run code** with minimal placeholders.
+ - Provide install/run/test snippets when you scaffold.
+
+7. **Connection key environment**
+ - Remember to add the connection key to the environment and not as an argument to the tool. As PLATFORM_CONNECTION_KEY (i.e. GMAIL_CONNECTION_KEY)
+
+8. **Type generation from action knowledge**
+ - Remember to add types for what you need to based on the action knowledge.
+
+---
+
+## 1) Pica MCP Utilities (Call These First)
+
+When asked to build a tool or MCP, follow this order:
+
+1) **list_pica_integrations**
+ _Goal_: Surface connectable platforms and their slugs/ids.
+ _User help_: Tell the user how to add/authorize integrations at `https://app.picaos.com/connections`.
+
+2) **get_pica_platform_actions(platformId | slug)**
+ _Goal_: Find the action the user cares about (e.g., Gmail `listMessages`, Notion `queryDatabase`, Slack `chat.postMessage`).
+
+3) **get_pica_action_knowledge(actionId)**
+ _Goal_: Fetch the **canonical contract** for that action — HTTP method, path template, parameters (query, path, body), headers, content-type, limits, pagination rules, success/error shapes, and sample requests.
+
+> Only after step (3) do you write code.
+
+---
+
+## 2) Pica Tool Executor (Boilerplate Example)
+
+> **Note**: This is **boilerplate** — do **not** treat as final or language-specific. It simply shows how to call the Pica passthrough API. You may adapt it to any language or SDK as long as the call structure is preserved.
+
+```ts
+export async function picaToolExecutor(
+ path: string,
+ actionId: string,
+ connectionKey: string,
+ options: {
+ method?: string;
+ queryParams?: URLSearchParams;
+ body?: any;
+ contentType?: string;
+ } = {}
+) {
+ const { method = 'GET', queryParams, body, contentType } = options;
+
+ const baseUrl = 'https://api.picaos.com/v1/passthrough';
+ const url = queryParams
+ ? `${baseUrl}${path}?${queryParams.toString()}`
+ : `${baseUrl}${path}`;
+
+ // Default to JSON unless overridden by action knowledge
+ const headers: Record = {
+ 'content-type': contentType || 'application/json',
+ 'x-pica-secret': process.env.PICA_API_KEY || '',
+ 'x-pica-connection-key': connectionKey,
+ 'x-pica-action-id': actionId,
+ };
+
+ const fetchOptions: RequestInit = { method, headers };
+
+ if (body && method !== 'GET') {
+ fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
+ }
+
+ const response = await fetch(url, fetchOptions);
+ if (!response.ok) {
+ const text = await response.text().catch(() => '');
+ throw new Error(`Pica API call failed: ${response.status} ${response.statusText} :: ${text}`);
+ }
+ return response.json().catch(() => ({}));
+}
+```
+
+**Key Points**
+- Default `content-type` = `application/json` unless overridden by `get_pica_action_knowledge`.
+- No Gmail-specific logic.
+- Example only — adapt freely to your language/runtime.
+
+---
+
+## 3) Building Tools (Vercel AI SDK & LangChain)
+
+1. Ask the user which **integration** & **action** they want (or infer from their ask).
+2. Call the Pica MCP utilities (Section 1).
+3. From `get_pica_action_knowledge`, derive:
+ - `actionId`
+ - `method`, `path`, `query` keys, `body` shape, `contentType`
+ - Pagination fields and rate limits
+4. Write the tool with a strict `inputSchema` and a clear `execute` that:
+ - Validates user input
+ - Builds query/body safely
+ - Calls `picaToolExecutor`
+ - Normalizes output (add a short `summary`)
+
+### Complete Gmail Tool Example
+
+Here's a real-world example of a Gmail tool that fetches email contents with proper filtering:
+
+```ts
+import { z } from 'zod';
+import { tool } from 'ai';
+import { picaToolExecutor } from '../picaToolExecutor';
+
+export const loadGmailEmails = tool({
+ description: 'Load Gmail emails with specific filtering by label and number. Returns sender, receiver, time, subject, and body for each email.',
+ inputSchema: z.object({
+ label: z.string().optional().describe('Gmail label to filter by (e.g., "INBOX", "SENT", "UNREAD", or custom labels)'),
+ numberOfEmails: z.number().min(1).max(50).default(10).describe('Number of emails to retrieve (1-50, default: 10)'),
+ query: z.string().optional().describe('Additional Gmail search query (e.g., "from:john@example.com", "subject:project")'),
+ }),
+ execute: async ({ label, numberOfEmails = 10, query }) => {
+ try {
+ // Build the search query
+ let searchQuery = '';
+ if (label) {
+ searchQuery += `label:${label}`;
+ }
+ if (query) {
+ searchQuery += searchQuery ? ` ${query}` : query;
+ }
+
+ // Prepare query parameters for list messages
+ const queryParams = new URLSearchParams({
+ maxResults: numberOfEmails.toString(),
+ ...(searchQuery && { q: searchQuery })
+ });
+
+ const connectionKey = process.env.GMAIL_CONNECTION_KEY;
+
+ // First, get the list of message IDs using picaToolExecutor
+ const listMessagesResult = await picaToolExecutor(
+ '/users/me/messages',
+ 'conn_mod_def::F_JeIVCQAiA::oD2p47ZVSHu1tF_maldXVQ',
+ connectionKey,
+ { queryParams }
+ );
+
+ if (!listMessagesResult?.messages || listMessagesResult.messages.length === 0) {
+ return {
+ emails: [],
+ totalFound: 0,
+ message: 'No emails found matching the criteria',
+ summary: 'No emails found matching the criteria'
+ };
+ }
+
+ // Extract email details from each message
+ const emails = [];
+
+ for (const messageRef of listMessagesResult.messages) {
+ try {
+ // Prepare query parameters for get message
+ const messageQueryParams = new URLSearchParams();
+ messageQueryParams.set('format', 'full');
+ messageQueryParams.append('metadataHeaders', 'From');
+ messageQueryParams.append('metadataHeaders', 'To');
+ messageQueryParams.append('metadataHeaders', 'Subject');
+ messageQueryParams.append('metadataHeaders', 'Date');
+
+ // Get full message details using picaToolExecutor
+ const messageResult = await picaToolExecutor(
+ `/users/me/messages/${messageRef.id}`,
+ 'conn_mod_def::F_JeIErCKGA::Q2ivQ5-QSyGYiEIZT867Dw',
+ connectionKey,
+ { queryParams: messageQueryParams }
+ );
+
+ if (messageResult?.payload?.headers) {
+ const headers = messageResult.payload.headers;
+
+ // Extract header information
+ const from = headers.find((h: any) => h.name.toLowerCase() === 'from')?.value || '';
+ const to = headers.find((h: any) => h.name.toLowerCase() === 'to')?.value || '';
+ const subject = headers.find((h: any) => h.name.toLowerCase() === 'subject')?.value || '';
+ const date = headers.find((h: any) => h.name.toLowerCase() === 'date')?.value || '';
+
+ // Extract body content
+ let body = '';
+ if (messageResult.payload.body?.data) {
+ // Decode base64 body
+ body = Buffer.from(messageResult.payload.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ } else if (messageResult.payload.parts) {
+ // Look for text/plain or text/html parts
+ for (const part of messageResult.payload.parts) {
+ if (part.mimeType === 'text/plain' && part.body?.data) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ break;
+ } else if (part.mimeType === 'text/html' && part.body?.data && !body) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ }
+ }
+ }
+
+ emails.push({
+ sender: from,
+ receiver: to,
+ time: date,
+ subject: subject,
+ body: body.substring(0, 2000) + (body.length > 2000 ? '...' : ''), // Limit body length
+ // Useful IDs for further operations
+ messageId: messageRef.id,
+ threadId: messageResult.threadId || messageRef.threadId || '',
+ labelIds: messageResult.labelIds || [],
+ historyId: messageResult.historyId || '',
+ internalDate: messageResult.internalDate || '',
+ snippet: messageResult.snippet || body.substring(0, 100) + (body.length > 100 ? '...' : '')
+ });
+ }
+ } catch (messageError) {
+ console.warn(`Failed to get details for message ${messageRef.id}:`, messageError);
+ // Continue with other messages
+ }
+ }
+
+ return {
+ emails,
+ totalFound: emails.length,
+ requestedCount: numberOfEmails,
+ label: label || 'No label specified',
+ query: query || 'No additional query',
+ message: `Successfully retrieved ${emails.length} emails`,
+ summary: `Retrieved ${emails.length} Gmail emails${label ? ` from ${label}` : ''}${query ? ` matching "${query}"` : ''}`
+ };
+
+ } catch (error) {
+ console.error('Gmail load error:', error);
+ return {
+ emails: [],
+ totalFound: 0,
+ error: String(error),
+ message: `Failed to load Gmail emails: ${error}`,
+ summary: `Failed to load Gmail emails: ${error}`
+ };
+ }
+ },
+});
+```
+
+### Key Implementation Patterns
+
+1. **Multiple API calls**: List messages first, then fetch details for each
+2. **Proper error handling**: Try-catch blocks and graceful degradation
+3. **Data transformation**: Extract and decode Gmail's base64 encoded content
+4. **Pagination support**: Use maxResults and search queries
+5. **Rich return format**: Include both raw data and user-friendly summaries
+
+---
+
+## 4) MCP Server Implementation (Gmail Example)
+
+For building complete MCP servers with Pica integration, follow this structure:
+
+### Project Structure
+```
+gmail-mcp-server/
+├── package.json
+├── tsconfig.json
+├── src/
+│ ├── index.ts # Main MCP server
+│ ├── tools/
+│ │ ├── gmail.ts # Gmail tool implementations
+│ │ └── index.ts # Tool registry
+│ └── utils/
+│ └── pica.ts # Pica executor
+└── dist/ # Compiled output
+```
+
+### package.json
+```json
+{
+ "name": "gmail-mcp-server",
+ "version": "1.0.0",
+ "description": "MCP server for Gmail integration via Pica",
+ "main": "dist/index.js",
+ "scripts": {
+ "build": "tsc",
+ "dev": "tsx src/index.ts",
+ "start": "node dist/index.js"
+ },
+ "dependencies": {
+ "@modelcontextprotocol/sdk": "^1.0.0",
+ "zod": "^3.23.8"
+ },
+ "devDependencies": {
+ "@types/node": "^20.0.0",
+ "tsx": "^4.0.0",
+ "typescript": "^5.0.0"
+ }
+}
+```
+
+### src/index.ts (Main MCP Server)
+```ts
+#!/usr/bin/env node
+import { Server } from '@modelcontextprotocol/sdk/server/index.js';
+import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
+import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
+import { gmailTools } from './tools/gmail.js';
+
+class GmailMCPServer {
+ private server: Server;
+
+ constructor() {
+ this.server = new Server(
+ {
+ name: 'gmail-mcp-server',
+ version: '1.0.0',
+ description: 'MCP server for Gmail integration via Pica'
+ },
+ {
+ capabilities: {
+ tools: {},
+ },
+ }
+ );
+
+ this.setupHandlers();
+ }
+
+ private setupHandlers() {
+ // List available tools
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
+ return {
+ tools: [
+ {
+ name: 'load_gmail_emails',
+ description: 'Load Gmail emails with specific filtering by label and number. Returns sender, receiver, time, subject, and body for each email.',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ label: {
+ type: 'string',
+ description: 'Gmail label to filter by (e.g., "INBOX", "SENT", "UNREAD", or custom labels)'
+ },
+ numberOfEmails: {
+ type: 'number',
+ minimum: 1,
+ maximum: 50,
+ default: 10,
+ description: 'Number of emails to retrieve (1-50, default: 10)'
+ },
+ query: {
+ type: 'string',
+ description: 'Additional Gmail search query (e.g., "from:john@example.com", "subject:project")'
+ }
+ },
+ required: []
+ }
+ }
+ ]
+ };
+ });
+
+ // Execute tools
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
+ const { name, arguments: args } = request.params;
+
+ try {
+ switch (name) {
+ case 'load_gmail_emails':
+ return await gmailTools.loadEmails(args);
+ default:
+ throw new Error(`Unknown tool: ${name}`);
+ }
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `Error executing ${name}: ${error instanceof Error ? error.message : String(error)}`
+ }
+ ],
+ isError: true
+ };
+ }
+ });
+ }
+
+ async run() {
+ const transport = new StdioServerTransport();
+ await this.server.connect(transport);
+ console.error('Gmail MCP Server running on stdio');
+ }
+}
+
+const server = new GmailMCPServer();
+server.run().catch(console.error);
+```
+
+### src/tools/gmail.ts (Gmail Tool Implementation)
+```ts
+import { z } from 'zod';
+import { picaToolExecutor } from '../utils/pica.js';
+
+const LoadGmailEmailsSchema = z.object({
+ label: z.string().optional(),
+ numberOfEmails: z.number().min(1).max(50).default(10),
+ query: z.string().optional()
+});
+
+export const gmailTools = {
+ async loadEmails(args: any) {
+ const input = LoadGmailEmailsSchema.parse(args);
+
+ if (!process.env.PICA_API_KEY) {
+ throw new Error('PICA_API_KEY environment variable is required');
+ }
+
+ const connectionKey = process.env.GMAIL_CONNECTION_KEY;
+
+ try {
+ // Build the search query
+ let searchQuery = '';
+ if (input.label) {
+ searchQuery += `label:${input.label}`;
+ }
+ if (input.query) {
+ searchQuery += searchQuery ? ` ${input.query}` : input.query;
+ }
+
+ // First, get the list of message IDs
+ const queryParams = new URLSearchParams({
+ maxResults: input.numberOfEmails.toString(),
+ ...(searchQuery && { q: searchQuery })
+ });
+
+ const listMessagesResult = await picaToolExecutor(
+ '/users/me/messages',
+ 'conn_mod_def::F_JeIVCQAiA::oD2p47ZVSHu1tF_maldXVQ',
+ connectionKey,
+ { queryParams }
+ );
+
+ if (!listMessagesResult?.messages || listMessagesResult.messages.length === 0) {
+ return {
+ content: [
+ {
+ type: 'text',
+ text: JSON.stringify({
+ emails: [],
+ totalFound: 0,
+ message: 'No emails found matching the criteria'
+ }, null, 2)
+ }
+ ]
+ };
+ }
+
+ // Get details for each message
+ const emails = [];
+ for (const messageRef of listMessagesResult.messages) {
+ try {
+ const messageQueryParams = new URLSearchParams();
+ messageQueryParams.set('format', 'full');
+ messageQueryParams.append('metadataHeaders', 'From');
+ messageQueryParams.append('metadataHeaders', 'To');
+ messageQueryParams.append('metadataHeaders', 'Subject');
+ messageQueryParams.append('metadataHeaders', 'Date');
+
+ const messageResult = await picaToolExecutor(
+ `/users/me/messages/${messageRef.id}`,
+ 'conn_mod_def::F_JeIErCKGA::Q2ivQ5-QSyGYiEIZT867Dw',
+ connectionKey,
+ { queryParams: messageQueryParams }
+ );
+
+ if (messageResult?.payload?.headers) {
+ const headers = messageResult.payload.headers;
+
+ const from = headers.find((h: any) => h.name.toLowerCase() === 'from')?.value || '';
+ const to = headers.find((h: any) => h.name.toLowerCase() === 'to')?.value || '';
+ const subject = headers.find((h: any) => h.name.toLowerCase() === 'subject')?.value || '';
+ const date = headers.find((h: any) => h.name.toLowerCase() === 'date')?.value || '';
+
+ // Extract and decode body content
+ let body = '';
+ if (messageResult.payload.body?.data) {
+ body = Buffer.from(messageResult.payload.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ } else if (messageResult.payload.parts) {
+ for (const part of messageResult.payload.parts) {
+ if (part.mimeType === 'text/plain' && part.body?.data) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ break;
+ } else if (part.mimeType === 'text/html' && part.body?.data && !body) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ }
+ }
+ }
+
+ emails.push({
+ sender: from,
+ receiver: to,
+ time: date,
+ subject: subject,
+ body: body.substring(0, 2000) + (body.length > 2000 ? '...' : ''),
+ messageId: messageRef.id,
+ threadId: messageResult.threadId || messageRef.threadId || '',
+ snippet: messageResult.snippet || body.substring(0, 100) + (body.length > 100 ? '...' : '')
+ });
+ }
+ } catch (messageError) {
+ console.warn(`Failed to get details for message ${messageRef.id}:`, messageError);
+ }
+ }
+
+ return {
+ content: [
+ {
+ type: 'text',
+ text: JSON.stringify({
+ emails,
+ totalFound: emails.length,
+ requestedCount: input.numberOfEmails,
+ label: input.label || 'No label specified',
+ query: input.query || 'No additional query',
+ summary: `Retrieved ${emails.length} Gmail emails${input.label ? ` from ${input.label}` : ''}${input.query ? ` matching "${input.query}"` : ''}`
+ }, null, 2)
+ }
+ ]
+ };
+ } catch (error) {
+ throw new Error(`Failed to load Gmail emails: ${error instanceof Error ? error.message : String(error)}`);
+ }
+ }
+};
+```
+
+### src/utils/pica.ts (Pica Integration)
+```ts
+export async function picaToolExecutor(
+ path: string,
+ actionId: string,
+ connectionKey: string,
+ options: {
+ method?: string;
+ queryParams?: URLSearchParams;
+ body?: any;
+ contentType?: string;
+ } = {}
+) {
+ const { method = 'GET', queryParams, body, contentType } = options;
+
+ const baseUrl = 'https://api.picaos.com/v1/passthrough';
+ const url = queryParams
+ ? `${baseUrl}${path}?${queryParams.toString()}`
+ : `${baseUrl}${path}`;
+
+ const headers: Record = {
+ 'content-type': contentType || 'application/json',
+ 'x-pica-secret': process.env.PICA_API_KEY || '',
+ 'x-pica-connection-key': connectionKey,
+ 'x-pica-action-id': actionId,
+ };
+
+ const fetchOptions: RequestInit = { method, headers };
+
+ if (body && method !== 'GET') {
+ fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
+ }
+
+ const response = await fetch(url, fetchOptions);
+ if (!response.ok) {
+ const text = await response.text().catch(() => '');
+ throw new Error(`Pica API call failed: ${response.status} ${response.statusText} :: ${text}`);
+ }
+ return response.json().catch(() => ({}));
+}
+```
+
+### MCP Configuration
+Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
+
+```json
+{
+ "mcpServers": {
+ "gmail": {
+ "command": "node",
+ "args": ["/path/to/gmail-mcp-server/dist/index.js"],
+ "env": {
+ "PICA_API_KEY": "your-pica-api-key"
+ }
+ }
+ }
+}
+```
+
+---
+
+## 5) Pagination, Rate Limits, and Errors
+
+- Use fields defined by `get_pica_action_knowledge` (e.g., `nextPageToken`, `cursor`, `page`, `limit`).
+- Loop until requested `limit` is reached or no `next` token remains.
+- On `429`, backoff before retrying.
+- Always return meaningful error messages and structured responses.
+
+---
+
+## 6) Security & Secrets
+
+- Require `PICA_API_KEY` at runtime.
+- Treat `{PLATFORM}_CONNECTION_KEY` as sensitive.
+- No secrets in logs or errors.
+- Validate all inputs with Zod schemas.
+
+---
+
+## 7) Project Detection (No Overwrite)
+
+- If project markers exist (`package.json`, `src/`, `.git`, etc.), **do not** scaffold new project.
+- Only add minimal new files for new tools or MCP endpoints.
+
+---
+
+## 8) Developer Experience
+
+- Provide complete installation instructions:
+ - `npm install @modelcontextprotocol/sdk zod`
+ - `npm install -D @types/node tsx typescript`
+- Build and run scripts:
+ - `"build": "tsc"`
+ - `"dev": "tsx src/index.ts"`
+ - `"start": "node dist/index.js"`
+
+---
+
+## 9) Done Criteria
+
+- Used Pica MCP discovery before coding
+- MCP server/tool compiles and runs with `PICA_API_KEY` + `{PLATFORM}_CONNECTION_KEY`
+- Tools are properly registered and callable
+- Input/output validation with Zod schemas
+- Error handling with meaningful responses
+- Follows MCP protocol correctly
+- Pagination & rate-limits handled if needed
+- Minimal changes to existing project structure
+
+---
diff --git a/buildkit/rules/windsurf/buildkit.md b/buildkit/rules/windsurf/buildkit.md
new file mode 100644
index 00000000..3f97825a
--- /dev/null
+++ b/buildkit/rules/windsurf/buildkit.md
@@ -0,0 +1,677 @@
+---
+description:
+globs:
+alwaysApply: true
+---
+
+# Pica Buildkit – LLM Rules
+
+**Role**
+You are an expert integration developer working with **Pica MCP**. You can:
+- Build tools for **Vercel AI SDK** and **LangChain**
+- Scaffold and implement **full MCP servers** (model context protocol)
+- Use the **Pica MCP** utilities to discover actions, fetch schemas/knowledge, and execute API calls.
+
+Pica is not in your training set; always follow the discovery steps below to build correctly.
+
+---
+
+## 0) Hard Requirements & Guardrails
+
+1. **Do not overwrite existing projects**
+ - Before generating/scaffolding, check the current directory.
+ - If a project is detected (e.g., `package.json`, `pnpm-lock.yaml`/`yarn.lock`/`package-lock.json`, `.git`, `mcp.json`, `src/` with buildkit markers), **do not** create a new project. Instead, add or modify files minimally and explicitly.
+
+2. **Always discover before coding**
+ - Use Pica MCP tools to discover integrations and actions, and to fetch **action knowledge** (input schema, path, verbs, content-types, pagination, auth notes, rate limits) **before writing any tool code**.
+
+3. **Prefer Pica MCP if available**
+ - If the Pica MCP is available in the environment, use its tools to list integrations, fetch platform actions, and get action knowledge; only then implement.
+
+4. **Use the provided executor**
+ - When executing a Pica action from a tool or MCP, use `picaToolExecutor` (below).
+ - Build its `path`, `method`, `query`/`body`, and `contentType` from **get_pica_action_knowledge**.
+
+5. **Secrets**
+ - Never print secrets. Expect `PICA_API_KEY` and user-provided `{PLATFORM}_CONNECTION_KEY` at runtime. Validate and fail fast if missing.
+
+6. **Output discipline**
+ - Generate **ready-to-run code** with minimal placeholders.
+ - Provide install/run/test snippets when you scaffold.
+
+7. **Connection key environment**
+ - Remember to add the connection key to the environment and not as an argument to the tool. As PLATFORM_CONNECTION_KEY (i.e. GMAIL_CONNECTION_KEY)
+
+8. **Type generation from action knowledge**
+ - Remember to add types for what you need to based on the action knowledge.
+
+---
+
+## 1) Pica MCP Utilities (Call These First)
+
+When asked to build a tool or MCP, follow this order:
+
+1) **list_pica_integrations**
+ _Goal_: Surface connectable platforms and their slugs/ids.
+ _User help_: Tell the user how to add/authorize integrations at `https://app.picaos.com/connections`.
+
+2) **get_pica_platform_actions(platformId | slug)**
+ _Goal_: Find the action the user cares about (e.g., Gmail `listMessages`, Notion `queryDatabase`, Slack `chat.postMessage`).
+
+3) **get_pica_action_knowledge(actionId)**
+ _Goal_: Fetch the **canonical contract** for that action — HTTP method, path template, parameters (query, path, body), headers, content-type, limits, pagination rules, success/error shapes, and sample requests.
+
+> Only after step (3) do you write code.
+
+---
+
+## 2) Pica Tool Executor (Boilerplate Example)
+
+> **Note**: This is **boilerplate** — do **not** treat as final or language-specific. It simply shows how to call the Pica passthrough API. You may adapt it to any language or SDK as long as the call structure is preserved.
+
+```ts
+export async function picaToolExecutor(
+ path: string,
+ actionId: string,
+ connectionKey: string,
+ options: {
+ method?: string;
+ queryParams?: URLSearchParams;
+ body?: any;
+ contentType?: string;
+ } = {}
+) {
+ const { method = 'GET', queryParams, body, contentType } = options;
+
+ const baseUrl = 'https://api.picaos.com/v1/passthrough';
+ const url = queryParams
+ ? `${baseUrl}${path}?${queryParams.toString()}`
+ : `${baseUrl}${path}`;
+
+ // Default to JSON unless overridden by action knowledge
+ const headers: Record = {
+ 'content-type': contentType || 'application/json',
+ 'x-pica-secret': process.env.PICA_API_KEY || '',
+ 'x-pica-connection-key': connectionKey,
+ 'x-pica-action-id': actionId,
+ };
+
+ const fetchOptions: RequestInit = { method, headers };
+
+ if (body && method !== 'GET') {
+ fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
+ }
+
+ const response = await fetch(url, fetchOptions);
+ if (!response.ok) {
+ const text = await response.text().catch(() => '');
+ throw new Error(`Pica API call failed: ${response.status} ${response.statusText} :: ${text}`);
+ }
+ return response.json().catch(() => ({}));
+}
+```
+
+**Key Points**
+- Default `content-type` = `application/json` unless overridden by `get_pica_action_knowledge`.
+- No Gmail-specific logic.
+- Example only — adapt freely to your language/runtime.
+
+---
+
+## 3) Building Tools (Vercel AI SDK & LangChain)
+
+1. Ask the user which **integration** & **action** they want (or infer from their ask).
+2. Call the Pica MCP utilities (Section 1).
+3. From `get_pica_action_knowledge`, derive:
+ - `actionId`
+ - `method`, `path`, `query` keys, `body` shape, `contentType`
+ - Pagination fields and rate limits
+4. Write the tool with a strict `inputSchema` and a clear `execute` that:
+ - Validates user input
+ - Builds query/body safely
+ - Calls `picaToolExecutor`
+ - Normalizes output (add a short `summary`)
+
+### Complete Gmail Tool Example
+
+Here's a real-world example of a Gmail tool that fetches email contents with proper filtering:
+
+```ts
+import { z } from 'zod';
+import { tool } from 'ai';
+import { picaToolExecutor } from '../picaToolExecutor';
+
+export const loadGmailEmails = tool({
+ description: 'Load Gmail emails with specific filtering by label and number. Returns sender, receiver, time, subject, and body for each email.',
+ inputSchema: z.object({
+ label: z.string().optional().describe('Gmail label to filter by (e.g., "INBOX", "SENT", "UNREAD", or custom labels)'),
+ numberOfEmails: z.number().min(1).max(50).default(10).describe('Number of emails to retrieve (1-50, default: 10)'),
+ query: z.string().optional().describe('Additional Gmail search query (e.g., "from:john@example.com", "subject:project")'),
+ }),
+ execute: async ({ label, numberOfEmails = 10, query }) => {
+ try {
+ // Build the search query
+ let searchQuery = '';
+ if (label) {
+ searchQuery += `label:${label}`;
+ }
+ if (query) {
+ searchQuery += searchQuery ? ` ${query}` : query;
+ }
+
+ // Prepare query parameters for list messages
+ const queryParams = new URLSearchParams({
+ maxResults: numberOfEmails.toString(),
+ ...(searchQuery && { q: searchQuery })
+ });
+
+ const connectionKey = process.env.GMAIL_CONNECTION_KEY;
+
+ // First, get the list of message IDs using picaToolExecutor
+ const listMessagesResult = await picaToolExecutor(
+ '/users/me/messages',
+ 'conn_mod_def::F_JeIVCQAiA::oD2p47ZVSHu1tF_maldXVQ',
+ connectionKey,
+ { queryParams }
+ );
+
+ if (!listMessagesResult?.messages || listMessagesResult.messages.length === 0) {
+ return {
+ emails: [],
+ totalFound: 0,
+ message: 'No emails found matching the criteria',
+ summary: 'No emails found matching the criteria'
+ };
+ }
+
+ // Extract email details from each message
+ const emails = [];
+
+ for (const messageRef of listMessagesResult.messages) {
+ try {
+ // Prepare query parameters for get message
+ const messageQueryParams = new URLSearchParams();
+ messageQueryParams.set('format', 'full');
+ messageQueryParams.append('metadataHeaders', 'From');
+ messageQueryParams.append('metadataHeaders', 'To');
+ messageQueryParams.append('metadataHeaders', 'Subject');
+ messageQueryParams.append('metadataHeaders', 'Date');
+
+ // Get full message details using picaToolExecutor
+ const messageResult = await picaToolExecutor(
+ `/users/me/messages/${messageRef.id}`,
+ 'conn_mod_def::F_JeIErCKGA::Q2ivQ5-QSyGYiEIZT867Dw',
+ connectionKey,
+ { queryParams: messageQueryParams }
+ );
+
+ if (messageResult?.payload?.headers) {
+ const headers = messageResult.payload.headers;
+
+ // Extract header information
+ const from = headers.find((h: any) => h.name.toLowerCase() === 'from')?.value || '';
+ const to = headers.find((h: any) => h.name.toLowerCase() === 'to')?.value || '';
+ const subject = headers.find((h: any) => h.name.toLowerCase() === 'subject')?.value || '';
+ const date = headers.find((h: any) => h.name.toLowerCase() === 'date')?.value || '';
+
+ // Extract body content
+ let body = '';
+ if (messageResult.payload.body?.data) {
+ // Decode base64 body
+ body = Buffer.from(messageResult.payload.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ } else if (messageResult.payload.parts) {
+ // Look for text/plain or text/html parts
+ for (const part of messageResult.payload.parts) {
+ if (part.mimeType === 'text/plain' && part.body?.data) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ break;
+ } else if (part.mimeType === 'text/html' && part.body?.data && !body) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ }
+ }
+ }
+
+ emails.push({
+ sender: from,
+ receiver: to,
+ time: date,
+ subject: subject,
+ body: body.substring(0, 2000) + (body.length > 2000 ? '...' : ''), // Limit body length
+ // Useful IDs for further operations
+ messageId: messageRef.id,
+ threadId: messageResult.threadId || messageRef.threadId || '',
+ labelIds: messageResult.labelIds || [],
+ historyId: messageResult.historyId || '',
+ internalDate: messageResult.internalDate || '',
+ snippet: messageResult.snippet || body.substring(0, 100) + (body.length > 100 ? '...' : '')
+ });
+ }
+ } catch (messageError) {
+ console.warn(`Failed to get details for message ${messageRef.id}:`, messageError);
+ // Continue with other messages
+ }
+ }
+
+ return {
+ emails,
+ totalFound: emails.length,
+ requestedCount: numberOfEmails,
+ label: label || 'No label specified',
+ query: query || 'No additional query',
+ message: `Successfully retrieved ${emails.length} emails`,
+ summary: `Retrieved ${emails.length} Gmail emails${label ? ` from ${label}` : ''}${query ? ` matching "${query}"` : ''}`
+ };
+
+ } catch (error) {
+ console.error('Gmail load error:', error);
+ return {
+ emails: [],
+ totalFound: 0,
+ error: String(error),
+ message: `Failed to load Gmail emails: ${error}`,
+ summary: `Failed to load Gmail emails: ${error}`
+ };
+ }
+ },
+});
+```
+
+### Key Implementation Patterns
+
+1. **Multiple API calls**: List messages first, then fetch details for each
+2. **Proper error handling**: Try-catch blocks and graceful degradation
+3. **Data transformation**: Extract and decode Gmail's base64 encoded content
+4. **Pagination support**: Use maxResults and search queries
+5. **Rich return format**: Include both raw data and user-friendly summaries
+
+---
+
+## 4) MCP Server Implementation (Gmail Example)
+
+For building complete MCP servers with Pica integration, follow this structure:
+
+### Project Structure
+```
+gmail-mcp-server/
+├── package.json
+├── tsconfig.json
+├── src/
+│ ├── index.ts # Main MCP server
+│ ├── tools/
+│ │ ├── gmail.ts # Gmail tool implementations
+│ │ └── index.ts # Tool registry
+│ └── utils/
+│ └── pica.ts # Pica executor
+└── dist/ # Compiled output
+```
+
+### package.json
+```json
+{
+ "name": "gmail-mcp-server",
+ "version": "1.0.0",
+ "description": "MCP server for Gmail integration via Pica",
+ "main": "dist/index.js",
+ "scripts": {
+ "build": "tsc",
+ "dev": "tsx src/index.ts",
+ "start": "node dist/index.js"
+ },
+ "dependencies": {
+ "@modelcontextprotocol/sdk": "^1.0.0",
+ "zod": "^3.23.8"
+ },
+ "devDependencies": {
+ "@types/node": "^20.0.0",
+ "tsx": "^4.0.0",
+ "typescript": "^5.0.0"
+ }
+}
+```
+
+### src/index.ts (Main MCP Server)
+```ts
+#!/usr/bin/env node
+import { Server } from '@modelcontextprotocol/sdk/server/index.js';
+import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
+import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
+import { gmailTools } from './tools/gmail.js';
+
+class GmailMCPServer {
+ private server: Server;
+
+ constructor() {
+ this.server = new Server(
+ {
+ name: 'gmail-mcp-server',
+ version: '1.0.0',
+ description: 'MCP server for Gmail integration via Pica'
+ },
+ {
+ capabilities: {
+ tools: {},
+ },
+ }
+ );
+
+ this.setupHandlers();
+ }
+
+ private setupHandlers() {
+ // List available tools
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
+ return {
+ tools: [
+ {
+ name: 'load_gmail_emails',
+ description: 'Load Gmail emails with specific filtering by label and number. Returns sender, receiver, time, subject, and body for each email.',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ label: {
+ type: 'string',
+ description: 'Gmail label to filter by (e.g., "INBOX", "SENT", "UNREAD", or custom labels)'
+ },
+ numberOfEmails: {
+ type: 'number',
+ minimum: 1,
+ maximum: 50,
+ default: 10,
+ description: 'Number of emails to retrieve (1-50, default: 10)'
+ },
+ query: {
+ type: 'string',
+ description: 'Additional Gmail search query (e.g., "from:john@example.com", "subject:project")'
+ }
+ },
+ required: []
+ }
+ }
+ ]
+ };
+ });
+
+ // Execute tools
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
+ const { name, arguments: args } = request.params;
+
+ try {
+ switch (name) {
+ case 'load_gmail_emails':
+ return await gmailTools.loadEmails(args);
+ default:
+ throw new Error(`Unknown tool: ${name}`);
+ }
+ } catch (error) {
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `Error executing ${name}: ${error instanceof Error ? error.message : String(error)}`
+ }
+ ],
+ isError: true
+ };
+ }
+ });
+ }
+
+ async run() {
+ const transport = new StdioServerTransport();
+ await this.server.connect(transport);
+ console.error('Gmail MCP Server running on stdio');
+ }
+}
+
+const server = new GmailMCPServer();
+server.run().catch(console.error);
+```
+
+### src/tools/gmail.ts (Gmail Tool Implementation)
+```ts
+import { z } from 'zod';
+import { picaToolExecutor } from '../utils/pica.js';
+
+const LoadGmailEmailsSchema = z.object({
+ label: z.string().optional(),
+ numberOfEmails: z.number().min(1).max(50).default(10),
+ query: z.string().optional()
+});
+
+export const gmailTools = {
+ async loadEmails(args: any) {
+ const input = LoadGmailEmailsSchema.parse(args);
+
+ if (!process.env.PICA_API_KEY) {
+ throw new Error('PICA_API_KEY environment variable is required');
+ }
+
+ const connectionKey = process.env.GMAIL_CONNECTION_KEY;
+
+ try {
+ // Build the search query
+ let searchQuery = '';
+ if (input.label) {
+ searchQuery += `label:${input.label}`;
+ }
+ if (input.query) {
+ searchQuery += searchQuery ? ` ${input.query}` : input.query;
+ }
+
+ // First, get the list of message IDs
+ const queryParams = new URLSearchParams({
+ maxResults: input.numberOfEmails.toString(),
+ ...(searchQuery && { q: searchQuery })
+ });
+
+ const listMessagesResult = await picaToolExecutor(
+ '/users/me/messages',
+ 'conn_mod_def::F_JeIVCQAiA::oD2p47ZVSHu1tF_maldXVQ',
+ connectionKey,
+ { queryParams }
+ );
+
+ if (!listMessagesResult?.messages || listMessagesResult.messages.length === 0) {
+ return {
+ content: [
+ {
+ type: 'text',
+ text: JSON.stringify({
+ emails: [],
+ totalFound: 0,
+ message: 'No emails found matching the criteria'
+ }, null, 2)
+ }
+ ]
+ };
+ }
+
+ // Get details for each message
+ const emails = [];
+ for (const messageRef of listMessagesResult.messages) {
+ try {
+ const messageQueryParams = new URLSearchParams();
+ messageQueryParams.set('format', 'full');
+ messageQueryParams.append('metadataHeaders', 'From');
+ messageQueryParams.append('metadataHeaders', 'To');
+ messageQueryParams.append('metadataHeaders', 'Subject');
+ messageQueryParams.append('metadataHeaders', 'Date');
+
+ const messageResult = await picaToolExecutor(
+ `/users/me/messages/${messageRef.id}`,
+ 'conn_mod_def::F_JeIErCKGA::Q2ivQ5-QSyGYiEIZT867Dw',
+ connectionKey,
+ { queryParams: messageQueryParams }
+ );
+
+ if (messageResult?.payload?.headers) {
+ const headers = messageResult.payload.headers;
+
+ const from = headers.find((h: any) => h.name.toLowerCase() === 'from')?.value || '';
+ const to = headers.find((h: any) => h.name.toLowerCase() === 'to')?.value || '';
+ const subject = headers.find((h: any) => h.name.toLowerCase() === 'subject')?.value || '';
+ const date = headers.find((h: any) => h.name.toLowerCase() === 'date')?.value || '';
+
+ // Extract and decode body content
+ let body = '';
+ if (messageResult.payload.body?.data) {
+ body = Buffer.from(messageResult.payload.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ } else if (messageResult.payload.parts) {
+ for (const part of messageResult.payload.parts) {
+ if (part.mimeType === 'text/plain' && part.body?.data) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ break;
+ } else if (part.mimeType === 'text/html' && part.body?.data && !body) {
+ body = Buffer.from(part.body.data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
+ }
+ }
+ }
+
+ emails.push({
+ sender: from,
+ receiver: to,
+ time: date,
+ subject: subject,
+ body: body.substring(0, 2000) + (body.length > 2000 ? '...' : ''),
+ messageId: messageRef.id,
+ threadId: messageResult.threadId || messageRef.threadId || '',
+ snippet: messageResult.snippet || body.substring(0, 100) + (body.length > 100 ? '...' : '')
+ });
+ }
+ } catch (messageError) {
+ console.warn(`Failed to get details for message ${messageRef.id}:`, messageError);
+ }
+ }
+
+ return {
+ content: [
+ {
+ type: 'text',
+ text: JSON.stringify({
+ emails,
+ totalFound: emails.length,
+ requestedCount: input.numberOfEmails,
+ label: input.label || 'No label specified',
+ query: input.query || 'No additional query',
+ summary: `Retrieved ${emails.length} Gmail emails${input.label ? ` from ${input.label}` : ''}${input.query ? ` matching "${input.query}"` : ''}`
+ }, null, 2)
+ }
+ ]
+ };
+ } catch (error) {
+ throw new Error(`Failed to load Gmail emails: ${error instanceof Error ? error.message : String(error)}`);
+ }
+ }
+};
+```
+
+### src/utils/pica.ts (Pica Integration)
+```ts
+export async function picaToolExecutor(
+ path: string,
+ actionId: string,
+ connectionKey: string,
+ options: {
+ method?: string;
+ queryParams?: URLSearchParams;
+ body?: any;
+ contentType?: string;
+ } = {}
+) {
+ const { method = 'GET', queryParams, body, contentType } = options;
+
+ const baseUrl = 'https://api.picaos.com/v1/passthrough';
+ const url = queryParams
+ ? `${baseUrl}${path}?${queryParams.toString()}`
+ : `${baseUrl}${path}`;
+
+ const headers: Record = {
+ 'content-type': contentType || 'application/json',
+ 'x-pica-secret': process.env.PICA_API_KEY || '',
+ 'x-pica-connection-key': connectionKey,
+ 'x-pica-action-id': actionId,
+ };
+
+ const fetchOptions: RequestInit = { method, headers };
+
+ if (body && method !== 'GET') {
+ fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
+ }
+
+ const response = await fetch(url, fetchOptions);
+ if (!response.ok) {
+ const text = await response.text().catch(() => '');
+ throw new Error(`Pica API call failed: ${response.status} ${response.statusText} :: ${text}`);
+ }
+ return response.json().catch(() => ({}));
+}
+```
+
+### MCP Configuration
+Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
+
+```json
+{
+ "mcpServers": {
+ "gmail": {
+ "command": "node",
+ "args": ["/path/to/gmail-mcp-server/dist/index.js"],
+ "env": {
+ "PICA_API_KEY": "your-pica-api-key"
+ }
+ }
+ }
+}
+```
+
+---
+
+## 5) Pagination, Rate Limits, and Errors
+
+- Use fields defined by `get_pica_action_knowledge` (e.g., `nextPageToken`, `cursor`, `page`, `limit`).
+- Loop until requested `limit` is reached or no `next` token remains.
+- On `429`, backoff before retrying.
+- Always return meaningful error messages and structured responses.
+
+---
+
+## 6) Security & Secrets
+
+- Require `PICA_API_KEY` at runtime.
+- Treat `{PLATFORM}_CONNECTION_KEY` as sensitive.
+- No secrets in logs or errors.
+- Validate all inputs with Zod schemas.
+
+---
+
+## 7) Project Detection (No Overwrite)
+
+- If project markers exist (`package.json`, `src/`, `.git`, etc.), **do not** scaffold new project.
+- Only add minimal new files for new tools or MCP endpoints.
+
+---
+
+## 8) Developer Experience
+
+- Provide complete installation instructions:
+ - `npm install @modelcontextprotocol/sdk zod`
+ - `npm install -D @types/node tsx typescript`
+- Build and run scripts:
+ - `"build": "tsc"`
+ - `"dev": "tsx src/index.ts"`
+ - `"start": "node dist/index.js"`
+
+---
+
+## 9) Done Criteria
+
+- Used Pica MCP discovery before coding
+- MCP server/tool compiles and runs with `PICA_API_KEY` + `{PLATFORM}_CONNECTION_KEY`
+- Tools are properly registered and callable
+- Input/output validation with Zod schemas
+- Error handling with meaningful responses
+- Follows MCP protocol correctly
+- Pagination & rate-limits handled if needed
+- Minimal changes to existing project structure
+
+---
diff --git a/.dockerignore b/core/.dockerignore
similarity index 100%
rename from .dockerignore
rename to core/.dockerignore
diff --git a/.env-example b/core/.env-example
similarity index 100%
rename from .env-example
rename to core/.env-example
diff --git a/Cargo.lock b/core/Cargo.lock
similarity index 100%
rename from Cargo.lock
rename to core/Cargo.lock
diff --git a/Cargo.toml b/core/Cargo.toml
similarity index 100%
rename from Cargo.toml
rename to core/Cargo.toml
diff --git a/Dockerfile.common b/core/Dockerfile.common
similarity index 100%
rename from Dockerfile.common
rename to core/Dockerfile.common
diff --git a/core/README.md b/core/README.md
new file mode 100644
index 00000000..7cd184b0
--- /dev/null
+++ b/core/README.md
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+Pica, The AI Integrations Solution
+
+
+
+ Website
+ ·
+ Documentation
+ ·
+ Dashboard
+ ·
+ Changelog
+ ·
+ X
+ ·
+ LinkedIn
+
+
+
+---
+
+Pica gives every builder instant, reliable access to the tools they need—no keys, no configs, no headaches.
+
+## Why Pica?
+
+Pica simplifies AI agent development with our four core products:
+
+✅ OneTool – Connect agents to [100+ APIs and tools](https://app.picaos.com/tools) with a single SDK.
+✅ AuthKit – Secure authentication for seamless tool integration.
+✅ BuildKit - Empower vibe coding with integrations that work zero-shot.
+
+Pica also provides full logging and action traceability, giving developers complete visibility into their agents’ decisions and activities. Our tools simplify building and running AI agents so developers can focus on results.
+
+## Getting started
+
+### Install
+
+```bash
+npm install @picahq/ai
+```
+
+### Setup
+
+1. Create a new [Pica account](https://app.picaos.com)
+2. Create a Connection via the [Dashboard](https://app.picaos.com/connections)
+3. Create an [API key](https://app.picaos.com/settings/api-keys)
+4. Set the API key as an environment variable: `PICA_SECRET_KEY=`
+
+### Example Usage
+
+Below is an example demonstrating how to integrate the [Pica OneTool](https://www.npmjs.com/package/@picahq/ai) with the [Vercel AI SDK](https://www.npmjs.com/package/ai) for a GitHub use case:
+
+```typescript
+import { openai } from "@ai-sdk/openai";
+import { generateText } from "ai";
+import { Pica } from "@picahq/ai";
+import * as dotenv from "dotenv";
+dotenv.config();
+
+const pica = new Pica(process.env.PICA_SECRET_KEY!, {
+ connectors: ["*"]
+});
+
+async function runAgentTask(message: string): Promise {
+ const system = await pica.generateSystemPrompt();
+
+ const { text } = await generateText({
+ model: openai("gpt-4.1"),
+ system,
+ prompt: message,
+ tools: { ...pica.oneTool },
+ maxSteps: 10,
+ });
+
+ return text;
+}
+
+runAgentTask("Star the repo picahq/pica with github")
+ .then((text) => {
+ console.log(text);
+ })
+ .catch(console.error);
+```
+
+[](https://replit.com/@picahq/Pica-or-GitHub-Star-Demo)
+
+
+For more use cases, visit our [Use Cases Library](https://www.picaos.com/community/use-cases) or our [Awesome Pica Repository](https://github.com/picahq/awesome-pica).
+
+### Next.js Integration
+
+⭐️ You can see a full Next.js demo [here](https://github.com/picahq/onetool-demo)
+
+
+> For more examples and detailed documentation, check out our [SDK documentation](https://docs.picaos.com/sdk/vercel-ai).
+
+---
+
+## Running Pica locally
+
+> [!IMPORTANT]
+> The Pica dashboard is going open source! Stay tuned for the big release 🚀
+
+### Prerequisites
+
+* [Docker](https://docs.docker.com/engine/)
+* [Docker Compose](https://docs.docker.com/compose/)
+
+### Step 1: Install the Pica CLI
+
+```sh
+npm install -g @picahq/cli
+```
+
+### Step 2: Initialize the Pica CLI
+
+To generate the configuration file, run:
+
+```shell
+pica init
+```
+
+### Step 3: Start the Pica Server
+
+```sh
+pica start
+```
+
+> All the inputs are required. Seeding is optional, but recommended when running the command for the first time.
+
+##### Example
+
+```Shell
+# To start the docker containers
+pica start
+Enter the IOS Crypto Secret (32 characters long): xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+Do you want to seed? (Y/N) y
+```
+
+**The Pica API will be available at `http://localhost:3005` 🚀**
+
+To stop the docker containers, simply run:
+
+```Shell
+pica stop
+```
+
+
+## License
+
+Pica is released under the [**GPL-3.0 license**](LICENSE).
diff --git a/api/Cargo.toml b/core/api/Cargo.toml
similarity index 100%
rename from api/Cargo.toml
rename to core/api/Cargo.toml
diff --git a/api/Dockerfile b/core/api/Dockerfile
similarity index 100%
rename from api/Dockerfile
rename to core/api/Dockerfile
diff --git a/api/README.md b/core/api/README.md
similarity index 100%
rename from api/README.md
rename to core/api/README.md
diff --git a/api/src/domain/config.rs b/core/api/src/domain/config.rs
similarity index 100%
rename from api/src/domain/config.rs
rename to core/api/src/domain/config.rs
diff --git a/api/src/domain/metrics.rs b/core/api/src/domain/metrics.rs
similarity index 100%
rename from api/src/domain/metrics.rs
rename to core/api/src/domain/metrics.rs
diff --git a/api/src/domain/mod.rs b/core/api/src/domain/mod.rs
similarity index 100%
rename from api/src/domain/mod.rs
rename to core/api/src/domain/mod.rs
diff --git a/api/src/domain/track.rs b/core/api/src/domain/track.rs
similarity index 100%
rename from api/src/domain/track.rs
rename to core/api/src/domain/track.rs
diff --git a/api/src/helper/k8s_driver.rs b/core/api/src/helper/k8s_driver.rs
similarity index 100%
rename from api/src/helper/k8s_driver.rs
rename to core/api/src/helper/k8s_driver.rs
diff --git a/api/src/helper/mod.rs b/core/api/src/helper/mod.rs
similarity index 100%
rename from api/src/helper/mod.rs
rename to core/api/src/helper/mod.rs
diff --git a/api/src/helper/shape_mongo_filter.rs b/core/api/src/helper/shape_mongo_filter.rs
similarity index 100%
rename from api/src/helper/shape_mongo_filter.rs
rename to core/api/src/helper/shape_mongo_filter.rs
diff --git a/api/src/lib.rs b/core/api/src/lib.rs
similarity index 100%
rename from api/src/lib.rs
rename to core/api/src/lib.rs
diff --git a/api/src/logic/common_enum.rs b/core/api/src/logic/common_enum.rs
similarity index 100%
rename from api/src/logic/common_enum.rs
rename to core/api/src/logic/common_enum.rs
diff --git a/api/src/logic/common_model.rs b/core/api/src/logic/common_model.rs
similarity index 100%
rename from api/src/logic/common_model.rs
rename to core/api/src/logic/common_model.rs
diff --git a/api/src/logic/connection.rs b/core/api/src/logic/connection.rs
similarity index 100%
rename from api/src/logic/connection.rs
rename to core/api/src/logic/connection.rs
diff --git a/api/src/logic/connection_definition.rs b/core/api/src/logic/connection_definition.rs
similarity index 100%
rename from api/src/logic/connection_definition.rs
rename to core/api/src/logic/connection_definition.rs
diff --git a/api/src/logic/connection_model_definition.rs b/core/api/src/logic/connection_model_definition.rs
similarity index 100%
rename from api/src/logic/connection_model_definition.rs
rename to core/api/src/logic/connection_model_definition.rs
diff --git a/api/src/logic/connection_model_schema.rs b/core/api/src/logic/connection_model_schema.rs
similarity index 100%
rename from api/src/logic/connection_model_schema.rs
rename to core/api/src/logic/connection_model_schema.rs
diff --git a/api/src/logic/connection_oauth_definition.rs b/core/api/src/logic/connection_oauth_definition.rs
similarity index 100%
rename from api/src/logic/connection_oauth_definition.rs
rename to core/api/src/logic/connection_oauth_definition.rs
diff --git a/api/src/logic/event_access.rs b/core/api/src/logic/event_access.rs
similarity index 100%
rename from api/src/logic/event_access.rs
rename to core/api/src/logic/event_access.rs
diff --git a/api/src/logic/event_callback.rs b/core/api/src/logic/event_callback.rs
similarity index 100%
rename from api/src/logic/event_callback.rs
rename to core/api/src/logic/event_callback.rs
diff --git a/api/src/logic/events.rs b/core/api/src/logic/events.rs
similarity index 100%
rename from api/src/logic/events.rs
rename to core/api/src/logic/events.rs
diff --git a/api/src/logic/knowledge.rs b/core/api/src/logic/knowledge.rs
similarity index 100%
rename from api/src/logic/knowledge.rs
rename to core/api/src/logic/knowledge.rs
diff --git a/api/src/logic/metrics.rs b/core/api/src/logic/metrics.rs
similarity index 100%
rename from api/src/logic/metrics.rs
rename to core/api/src/logic/metrics.rs
diff --git a/api/src/logic/mod.rs b/core/api/src/logic/mod.rs
similarity index 100%
rename from api/src/logic/mod.rs
rename to core/api/src/logic/mod.rs
diff --git a/api/src/logic/oauth.rs b/core/api/src/logic/oauth.rs
similarity index 100%
rename from api/src/logic/oauth.rs
rename to core/api/src/logic/oauth.rs
diff --git a/api/src/logic/openapi/builder.rs b/core/api/src/logic/openapi/builder.rs
similarity index 100%
rename from api/src/logic/openapi/builder.rs
rename to core/api/src/logic/openapi/builder.rs
diff --git a/api/src/logic/openapi/mod.rs b/core/api/src/logic/openapi/mod.rs
similarity index 100%
rename from api/src/logic/openapi/mod.rs
rename to core/api/src/logic/openapi/mod.rs
diff --git a/api/src/logic/passthrough.rs b/core/api/src/logic/passthrough.rs
similarity index 100%
rename from api/src/logic/passthrough.rs
rename to core/api/src/logic/passthrough.rs
diff --git a/api/src/logic/platform.rs b/core/api/src/logic/platform.rs
similarity index 100%
rename from api/src/logic/platform.rs
rename to core/api/src/logic/platform.rs
diff --git a/api/src/logic/platform_page.rs b/core/api/src/logic/platform_page.rs
similarity index 100%
rename from api/src/logic/platform_page.rs
rename to core/api/src/logic/platform_page.rs
diff --git a/api/src/logic/schema_generator.rs b/core/api/src/logic/schema_generator.rs
similarity index 100%
rename from api/src/logic/schema_generator.rs
rename to core/api/src/logic/schema_generator.rs
diff --git a/api/src/logic/secrets.rs b/core/api/src/logic/secrets.rs
similarity index 100%
rename from api/src/logic/secrets.rs
rename to core/api/src/logic/secrets.rs
diff --git a/api/src/logic/tasks.rs b/core/api/src/logic/tasks.rs
similarity index 100%
rename from api/src/logic/tasks.rs
rename to core/api/src/logic/tasks.rs
diff --git a/api/src/logic/tracker.rs b/core/api/src/logic/tracker.rs
similarity index 100%
rename from api/src/logic/tracker.rs
rename to core/api/src/logic/tracker.rs
diff --git a/api/src/logic/unified.rs b/core/api/src/logic/unified.rs
similarity index 100%
rename from api/src/logic/unified.rs
rename to core/api/src/logic/unified.rs
diff --git a/api/src/logic/vault_connection.rs b/core/api/src/logic/vault_connection.rs
similarity index 100%
rename from api/src/logic/vault_connection.rs
rename to core/api/src/logic/vault_connection.rs
diff --git a/api/src/main.rs b/core/api/src/main.rs
similarity index 100%
rename from api/src/main.rs
rename to core/api/src/main.rs
diff --git a/api/src/middleware/header_auth.rs b/core/api/src/middleware/header_auth.rs
similarity index 100%
rename from api/src/middleware/header_auth.rs
rename to core/api/src/middleware/header_auth.rs
diff --git a/api/src/middleware/header_blocker.rs b/core/api/src/middleware/header_blocker.rs
similarity index 100%
rename from api/src/middleware/header_blocker.rs
rename to core/api/src/middleware/header_blocker.rs
diff --git a/api/src/middleware/header_passthrough.rs b/core/api/src/middleware/header_passthrough.rs
similarity index 100%
rename from api/src/middleware/header_passthrough.rs
rename to core/api/src/middleware/header_passthrough.rs
diff --git a/api/src/middleware/jwt_auth.rs b/core/api/src/middleware/jwt_auth.rs
similarity index 100%
rename from api/src/middleware/jwt_auth.rs
rename to core/api/src/middleware/jwt_auth.rs
diff --git a/api/src/middleware/mod.rs b/core/api/src/middleware/mod.rs
similarity index 100%
rename from api/src/middleware/mod.rs
rename to core/api/src/middleware/mod.rs
diff --git a/api/src/middleware/rate_limiter.rs b/core/api/src/middleware/rate_limiter.rs
similarity index 100%
rename from api/src/middleware/rate_limiter.rs
rename to core/api/src/middleware/rate_limiter.rs
diff --git a/api/src/router/mod.rs b/core/api/src/router/mod.rs
similarity index 100%
rename from api/src/router/mod.rs
rename to core/api/src/router/mod.rs
diff --git a/api/src/router/public.rs b/core/api/src/router/public.rs
similarity index 100%
rename from api/src/router/public.rs
rename to core/api/src/router/public.rs
diff --git a/api/src/router/secured_jwt.rs b/core/api/src/router/secured_jwt.rs
similarity index 100%
rename from api/src/router/secured_jwt.rs
rename to core/api/src/router/secured_jwt.rs
diff --git a/api/src/router/secured_key.rs b/core/api/src/router/secured_key.rs
similarity index 100%
rename from api/src/router/secured_key.rs
rename to core/api/src/router/secured_key.rs
diff --git a/api/src/server.rs b/core/api/src/server.rs
similarity index 100%
rename from api/src/server.rs
rename to core/api/src/server.rs
diff --git a/api/tests/checker.rs b/core/api/tests/checker.rs
similarity index 100%
rename from api/tests/checker.rs
rename to core/api/tests/checker.rs
diff --git a/api/tests/context.rs b/core/api/tests/context.rs
similarity index 100%
rename from api/tests/context.rs
rename to core/api/tests/context.rs
diff --git a/api/tests/http/auth.rs b/core/api/tests/http/auth.rs
similarity index 100%
rename from api/tests/http/auth.rs
rename to core/api/tests/http/auth.rs
diff --git a/api/tests/http/callback.rs b/core/api/tests/http/callback.rs
similarity index 100%
rename from api/tests/http/callback.rs
rename to core/api/tests/http/callback.rs
diff --git a/api/tests/http/connection.rs b/core/api/tests/http/connection.rs
similarity index 100%
rename from api/tests/http/connection.rs
rename to core/api/tests/http/connection.rs
diff --git a/api/tests/http/crud.rs b/core/api/tests/http/crud.rs
similarity index 100%
rename from api/tests/http/crud.rs
rename to core/api/tests/http/crud.rs
diff --git a/api/tests/http/mod.rs b/core/api/tests/http/mod.rs
similarity index 100%
rename from api/tests/http/mod.rs
rename to core/api/tests/http/mod.rs
diff --git a/api/tests/http/pagination.rs b/core/api/tests/http/pagination.rs
similarity index 100%
rename from api/tests/http/pagination.rs
rename to core/api/tests/http/pagination.rs
diff --git a/api/tests/http/passthrough.rs b/core/api/tests/http/passthrough.rs
similarity index 100%
rename from api/tests/http/passthrough.rs
rename to core/api/tests/http/passthrough.rs
diff --git a/api/tests/http/schema.rs b/core/api/tests/http/schema.rs
similarity index 100%
rename from api/tests/http/schema.rs
rename to core/api/tests/http/schema.rs
diff --git a/api/tests/http/unified.rs b/core/api/tests/http/unified.rs
similarity index 100%
rename from api/tests/http/unified.rs
rename to core/api/tests/http/unified.rs
diff --git a/api/tests/main.rs b/core/api/tests/main.rs
similarity index 100%
rename from api/tests/main.rs
rename to core/api/tests/main.rs
diff --git a/api/tests/resource/osentities_domain_connection_Connection.bson b/core/api/tests/resource/osentities_domain_connection_Connection.bson
similarity index 100%
rename from api/tests/resource/osentities_domain_connection_Connection.bson
rename to core/api/tests/resource/osentities_domain_connection_Connection.bson
diff --git a/api/tests/resource/osentities_domain_connection_Connection.json b/core/api/tests/resource/osentities_domain_connection_Connection.json
similarity index 100%
rename from api/tests/resource/osentities_domain_connection_Connection.json
rename to core/api/tests/resource/osentities_domain_connection_Connection.json
diff --git a/api/tests/resource/osentities_domain_connection_connection_definition_ConnectionDefinition.bson b/core/api/tests/resource/osentities_domain_connection_connection_definition_ConnectionDefinition.bson
similarity index 100%
rename from api/tests/resource/osentities_domain_connection_connection_definition_ConnectionDefinition.bson
rename to core/api/tests/resource/osentities_domain_connection_connection_definition_ConnectionDefinition.bson
diff --git a/api/tests/resource/osentities_domain_connection_connection_definition_ConnectionDefinition.json b/core/api/tests/resource/osentities_domain_connection_connection_definition_ConnectionDefinition.json
similarity index 100%
rename from api/tests/resource/osentities_domain_connection_connection_definition_ConnectionDefinition.json
rename to core/api/tests/resource/osentities_domain_connection_connection_definition_ConnectionDefinition.json
diff --git a/api/tests/resource/osentities_domain_connection_connection_model_definition_ConnectionModelDefinition.bson b/core/api/tests/resource/osentities_domain_connection_connection_model_definition_ConnectionModelDefinition.bson
similarity index 100%
rename from api/tests/resource/osentities_domain_connection_connection_model_definition_ConnectionModelDefinition.bson
rename to core/api/tests/resource/osentities_domain_connection_connection_model_definition_ConnectionModelDefinition.bson
diff --git a/api/tests/resource/osentities_domain_connection_connection_model_definition_ConnectionModelDefinition.json b/core/api/tests/resource/osentities_domain_connection_connection_model_definition_ConnectionModelDefinition.json
similarity index 100%
rename from api/tests/resource/osentities_domain_connection_connection_model_definition_ConnectionModelDefinition.json
rename to core/api/tests/resource/osentities_domain_connection_connection_model_definition_ConnectionModelDefinition.json
diff --git a/api/tests/resource/osentities_domain_connection_connection_model_schema_ConnectionModelSchema.bson b/core/api/tests/resource/osentities_domain_connection_connection_model_schema_ConnectionModelSchema.bson
similarity index 100%
rename from api/tests/resource/osentities_domain_connection_connection_model_schema_ConnectionModelSchema.bson
rename to core/api/tests/resource/osentities_domain_connection_connection_model_schema_ConnectionModelSchema.bson
diff --git a/api/tests/resource/osentities_domain_connection_connection_model_schema_ConnectionModelSchema.json b/core/api/tests/resource/osentities_domain_connection_connection_model_schema_ConnectionModelSchema.json
similarity index 100%
rename from api/tests/resource/osentities_domain_connection_connection_model_schema_ConnectionModelSchema.json
rename to core/api/tests/resource/osentities_domain_connection_connection_model_schema_ConnectionModelSchema.json
diff --git a/api/tests/resource/osentities_domain_schema_common_model_CommonEnum.bson b/core/api/tests/resource/osentities_domain_schema_common_model_CommonEnum.bson
similarity index 100%
rename from api/tests/resource/osentities_domain_schema_common_model_CommonEnum.bson
rename to core/api/tests/resource/osentities_domain_schema_common_model_CommonEnum.bson
diff --git a/api/tests/resource/osentities_domain_schema_common_model_CommonEnum.json b/core/api/tests/resource/osentities_domain_schema_common_model_CommonEnum.json
similarity index 100%
rename from api/tests/resource/osentities_domain_schema_common_model_CommonEnum.json
rename to core/api/tests/resource/osentities_domain_schema_common_model_CommonEnum.json
diff --git a/api/tests/resource/osentities_domain_schema_common_model_CommonModel.bson b/core/api/tests/resource/osentities_domain_schema_common_model_CommonModel.bson
similarity index 100%
rename from api/tests/resource/osentities_domain_schema_common_model_CommonModel.bson
rename to core/api/tests/resource/osentities_domain_schema_common_model_CommonModel.bson
diff --git a/api/tests/resource/osentities_domain_schema_common_model_CommonModel.json b/core/api/tests/resource/osentities_domain_schema_common_model_CommonModel.json
similarity index 100%
rename from api/tests/resource/osentities_domain_schema_common_model_CommonModel.json
rename to core/api/tests/resource/osentities_domain_schema_common_model_CommonModel.json
diff --git a/api/tests/standard/mod.rs b/core/api/tests/standard/mod.rs
similarity index 100%
rename from api/tests/standard/mod.rs
rename to core/api/tests/standard/mod.rs
diff --git a/archiver/Cargo.toml b/core/archiver/Cargo.toml
similarity index 100%
rename from archiver/Cargo.toml
rename to core/archiver/Cargo.toml
diff --git a/archiver/Dockerfile b/core/archiver/Dockerfile
similarity index 100%
rename from archiver/Dockerfile
rename to core/archiver/Dockerfile
diff --git a/archiver/README.md b/core/archiver/README.md
similarity index 100%
rename from archiver/README.md
rename to core/archiver/README.md
diff --git a/archiver/src/domain/config.rs b/core/archiver/src/domain/config.rs
similarity index 100%
rename from archiver/src/domain/config.rs
rename to core/archiver/src/domain/config.rs
diff --git a/archiver/src/domain/mod.rs b/core/archiver/src/domain/mod.rs
similarity index 100%
rename from archiver/src/domain/mod.rs
rename to core/archiver/src/domain/mod.rs
diff --git a/archiver/src/event/chosen.rs b/core/archiver/src/event/chosen.rs
similarity index 100%
rename from archiver/src/event/chosen.rs
rename to core/archiver/src/event/chosen.rs
diff --git a/archiver/src/event/completed.rs b/core/archiver/src/event/completed.rs
similarity index 100%
rename from archiver/src/event/completed.rs
rename to core/archiver/src/event/completed.rs
diff --git a/archiver/src/event/dumped.rs b/core/archiver/src/event/dumped.rs
similarity index 100%
rename from archiver/src/event/dumped.rs
rename to core/archiver/src/event/dumped.rs
diff --git a/archiver/src/event/failed.rs b/core/archiver/src/event/failed.rs
similarity index 100%
rename from archiver/src/event/failed.rs
rename to core/archiver/src/event/failed.rs
diff --git a/archiver/src/event/finished.rs b/core/archiver/src/event/finished.rs
similarity index 100%
rename from archiver/src/event/finished.rs
rename to core/archiver/src/event/finished.rs
diff --git a/archiver/src/event/mod.rs b/core/archiver/src/event/mod.rs
similarity index 100%
rename from archiver/src/event/mod.rs
rename to core/archiver/src/event/mod.rs
diff --git a/archiver/src/event/started.rs b/core/archiver/src/event/started.rs
similarity index 100%
rename from archiver/src/event/started.rs
rename to core/archiver/src/event/started.rs
diff --git a/archiver/src/event/uploaded.rs b/core/archiver/src/event/uploaded.rs
similarity index 100%
rename from archiver/src/event/uploaded.rs
rename to core/archiver/src/event/uploaded.rs
diff --git a/archiver/src/main.rs b/core/archiver/src/main.rs
similarity index 100%
rename from archiver/src/main.rs
rename to core/archiver/src/main.rs
diff --git a/archiver/src/storage/google_cloud.rs b/core/archiver/src/storage/google_cloud.rs
similarity index 100%
rename from archiver/src/storage/google_cloud.rs
rename to core/archiver/src/storage/google_cloud.rs
diff --git a/archiver/src/storage/mod.rs b/core/archiver/src/storage/mod.rs
similarity index 100%
rename from archiver/src/storage/mod.rs
rename to core/archiver/src/storage/mod.rs
diff --git a/cache/Cargo.toml b/core/cache/Cargo.toml
similarity index 100%
rename from cache/Cargo.toml
rename to core/cache/Cargo.toml
diff --git a/cache/README.md b/core/cache/README.md
similarity index 100%
rename from cache/README.md
rename to core/cache/README.md
diff --git a/cache/src/lib.rs b/core/cache/src/lib.rs
similarity index 100%
rename from cache/src/lib.rs
rename to core/cache/src/lib.rs
diff --git a/cache/src/local.rs b/core/cache/src/local.rs
similarity index 100%
rename from cache/src/local.rs
rename to core/cache/src/local.rs
diff --git a/cache/src/remote.rs b/core/cache/src/remote.rs
similarity index 100%
rename from cache/src/remote.rs
rename to core/cache/src/remote.rs
diff --git a/cli/Cargo.lock b/core/cli/Cargo.lock
similarity index 100%
rename from cli/Cargo.lock
rename to core/cli/Cargo.lock
diff --git a/cli/Cargo.toml b/core/cli/Cargo.toml
similarity index 100%
rename from cli/Cargo.toml
rename to core/cli/Cargo.toml
diff --git a/cli/README.md b/core/cli/README.md
similarity index 100%
rename from cli/README.md
rename to core/cli/README.md
diff --git a/cli/src/algebra/handler.rs b/core/cli/src/algebra/handler.rs
similarity index 100%
rename from cli/src/algebra/handler.rs
rename to core/cli/src/algebra/handler.rs
diff --git a/cli/src/algebra/mod.rs b/core/cli/src/algebra/mod.rs
similarity index 100%
rename from cli/src/algebra/mod.rs
rename to core/cli/src/algebra/mod.rs
diff --git a/cli/src/domain/config.rs b/core/cli/src/domain/config.rs
similarity index 100%
rename from cli/src/domain/config.rs
rename to core/cli/src/domain/config.rs
diff --git a/cli/src/domain/constant.rs b/core/cli/src/domain/constant.rs
similarity index 100%
rename from cli/src/domain/constant.rs
rename to core/cli/src/domain/constant.rs
diff --git a/cli/src/domain/context.rs b/core/cli/src/domain/context.rs
similarity index 100%
rename from cli/src/domain/context.rs
rename to core/cli/src/domain/context.rs
diff --git a/cli/src/domain/event.rs b/core/cli/src/domain/event.rs
similarity index 100%
rename from cli/src/domain/event.rs
rename to core/cli/src/domain/event.rs
diff --git a/cli/src/domain/mod.rs b/core/cli/src/domain/mod.rs
similarity index 100%
rename from cli/src/domain/mod.rs
rename to core/cli/src/domain/mod.rs
diff --git a/cli/src/domain/steps.rs b/core/cli/src/domain/steps.rs
similarity index 100%
rename from cli/src/domain/steps.rs
rename to core/cli/src/domain/steps.rs
diff --git a/cli/src/lib.rs b/core/cli/src/lib.rs
similarity index 100%
rename from cli/src/lib.rs
rename to core/cli/src/lib.rs
diff --git a/cli/src/main.rs b/core/cli/src/main.rs
similarity index 100%
rename from cli/src/main.rs
rename to core/cli/src/main.rs
diff --git a/cli/src/service/command.rs b/core/cli/src/service/command.rs
similarity index 100%
rename from cli/src/service/command.rs
rename to core/cli/src/service/command.rs
diff --git a/cli/src/service/helper.rs b/core/cli/src/service/helper.rs
similarity index 100%
rename from cli/src/service/helper.rs
rename to core/cli/src/service/helper.rs
diff --git a/cli/src/service/mod.rs b/core/cli/src/service/mod.rs
similarity index 100%
rename from cli/src/service/mod.rs
rename to core/cli/src/service/mod.rs
diff --git a/cli/src/service/printer.rs b/core/cli/src/service/printer.rs
similarity index 100%
rename from cli/src/service/printer.rs
rename to core/cli/src/service/printer.rs
diff --git a/cli/src/service/server.rs b/core/cli/src/service/server.rs
similarity index 100%
rename from cli/src/service/server.rs
rename to core/cli/src/service/server.rs
diff --git a/database/Cargo.toml b/core/database/Cargo.toml
similarity index 100%
rename from database/Cargo.toml
rename to core/database/Cargo.toml
diff --git a/database/Dockerfile b/core/database/Dockerfile
similarity index 100%
rename from database/Dockerfile
rename to core/database/Dockerfile
diff --git a/database/README.md b/core/database/README.md
similarity index 100%
rename from database/README.md
rename to core/database/README.md
diff --git a/database/src/algebra/init.rs b/core/database/src/algebra/init.rs
similarity index 100%
rename from database/src/algebra/init.rs
rename to core/database/src/algebra/init.rs
diff --git a/database/src/algebra/mod.rs b/core/database/src/algebra/mod.rs
similarity index 100%
rename from database/src/algebra/mod.rs
rename to core/database/src/algebra/mod.rs
diff --git a/database/src/algebra/storage.rs b/core/database/src/algebra/storage.rs
similarity index 100%
rename from database/src/algebra/storage.rs
rename to core/database/src/algebra/storage.rs
diff --git a/database/src/domain/mod.rs b/core/database/src/domain/mod.rs
similarity index 100%
rename from database/src/domain/mod.rs
rename to core/database/src/domain/mod.rs
diff --git a/database/src/domain/postgres.rs b/core/database/src/domain/postgres.rs
similarity index 100%
rename from database/src/domain/postgres.rs
rename to core/database/src/domain/postgres.rs
diff --git a/database/src/lib.rs b/core/database/src/lib.rs
similarity index 100%
rename from database/src/lib.rs
rename to core/database/src/lib.rs
diff --git a/database/src/logic/connection.rs b/core/database/src/logic/connection.rs
similarity index 100%
rename from database/src/logic/connection.rs
rename to core/database/src/logic/connection.rs
diff --git a/database/src/logic/mod.rs b/core/database/src/logic/mod.rs
similarity index 100%
rename from database/src/logic/mod.rs
rename to core/database/src/logic/mod.rs
diff --git a/database/src/main.rs b/core/database/src/main.rs
similarity index 100%
rename from database/src/main.rs
rename to core/database/src/main.rs
diff --git a/database/src/router/mod.rs b/core/database/src/router/mod.rs
similarity index 100%
rename from database/src/router/mod.rs
rename to core/database/src/router/mod.rs
diff --git a/database/src/server.rs b/core/database/src/server.rs
similarity index 100%
rename from database/src/server.rs
rename to core/database/src/server.rs
diff --git a/database/tests/context.rs b/core/database/tests/context.rs
similarity index 100%
rename from database/tests/context.rs
rename to core/database/tests/context.rs
diff --git a/database/tests/http/connection.rs b/core/database/tests/http/connection.rs
similarity index 100%
rename from database/tests/http/connection.rs
rename to core/database/tests/http/connection.rs
diff --git a/database/tests/http/mod.rs b/core/database/tests/http/mod.rs
similarity index 100%
rename from database/tests/http/mod.rs
rename to core/database/tests/http/mod.rs
diff --git a/database/tests/http/signal.rs b/core/database/tests/http/signal.rs
similarity index 100%
rename from database/tests/http/signal.rs
rename to core/database/tests/http/signal.rs
diff --git a/database/tests/main.rs b/core/database/tests/main.rs
similarity index 100%
rename from database/tests/main.rs
rename to core/database/tests/main.rs
diff --git a/docker-compose.data.yml b/core/docker-compose.data.yml
similarity index 100%
rename from docker-compose.data.yml
rename to core/docker-compose.data.yml
diff --git a/docker-compose.yml b/core/docker-compose.yml
similarity index 100%
rename from docker-compose.yml
rename to core/docker-compose.yml
diff --git a/oauth/.eslintignore b/core/oauth/.eslintignore
similarity index 100%
rename from oauth/.eslintignore
rename to core/oauth/.eslintignore
diff --git a/oauth/.eslintrc b/core/oauth/.eslintrc
similarity index 100%
rename from oauth/.eslintrc
rename to core/oauth/.eslintrc
diff --git a/oauth/.prettierrc b/core/oauth/.prettierrc
similarity index 100%
rename from oauth/.prettierrc
rename to core/oauth/.prettierrc
diff --git a/oauth/Dockerfile b/core/oauth/Dockerfile
similarity index 100%
rename from oauth/Dockerfile
rename to core/oauth/Dockerfile
diff --git a/oauth/README.md b/core/oauth/README.md
similarity index 100%
rename from oauth/README.md
rename to core/oauth/README.md
diff --git a/oauth/package.json b/core/oauth/package.json
similarity index 100%
rename from oauth/package.json
rename to core/oauth/package.json
diff --git a/oauth/src/connections/airtable/init.ts b/core/oauth/src/connections/airtable/init.ts
similarity index 100%
rename from oauth/src/connections/airtable/init.ts
rename to core/oauth/src/connections/airtable/init.ts
diff --git a/oauth/src/connections/airtable/refresh.ts b/core/oauth/src/connections/airtable/refresh.ts
similarity index 100%
rename from oauth/src/connections/airtable/refresh.ts
rename to core/oauth/src/connections/airtable/refresh.ts
diff --git a/oauth/src/connections/amazonAds/init.ts b/core/oauth/src/connections/amazonAds/init.ts
similarity index 100%
rename from oauth/src/connections/amazonAds/init.ts
rename to core/oauth/src/connections/amazonAds/init.ts
diff --git a/oauth/src/connections/amazonAds/refresh.ts b/core/oauth/src/connections/amazonAds/refresh.ts
similarity index 100%
rename from oauth/src/connections/amazonAds/refresh.ts
rename to core/oauth/src/connections/amazonAds/refresh.ts
diff --git a/oauth/src/connections/apollo/init.ts b/core/oauth/src/connections/apollo/init.ts
similarity index 100%
rename from oauth/src/connections/apollo/init.ts
rename to core/oauth/src/connections/apollo/init.ts
diff --git a/oauth/src/connections/apollo/refresh.ts b/core/oauth/src/connections/apollo/refresh.ts
similarity index 100%
rename from oauth/src/connections/apollo/refresh.ts
rename to core/oauth/src/connections/apollo/refresh.ts
diff --git a/oauth/src/connections/asana/init.ts b/core/oauth/src/connections/asana/init.ts
similarity index 100%
rename from oauth/src/connections/asana/init.ts
rename to core/oauth/src/connections/asana/init.ts
diff --git a/oauth/src/connections/asana/refresh.ts b/core/oauth/src/connections/asana/refresh.ts
similarity index 100%
rename from oauth/src/connections/asana/refresh.ts
rename to core/oauth/src/connections/asana/refresh.ts
diff --git a/oauth/src/connections/attio/init.ts b/core/oauth/src/connections/attio/init.ts
similarity index 100%
rename from oauth/src/connections/attio/init.ts
rename to core/oauth/src/connections/attio/init.ts
diff --git a/oauth/src/connections/attio/refresh.ts b/core/oauth/src/connections/attio/refresh.ts
similarity index 100%
rename from oauth/src/connections/attio/refresh.ts
rename to core/oauth/src/connections/attio/refresh.ts
diff --git a/oauth/src/connections/box/init.ts b/core/oauth/src/connections/box/init.ts
similarity index 100%
rename from oauth/src/connections/box/init.ts
rename to core/oauth/src/connections/box/init.ts
diff --git a/oauth/src/connections/box/refresh.ts b/core/oauth/src/connections/box/refresh.ts
similarity index 100%
rename from oauth/src/connections/box/refresh.ts
rename to core/oauth/src/connections/box/refresh.ts
diff --git a/oauth/src/connections/calendly/init.ts b/core/oauth/src/connections/calendly/init.ts
similarity index 100%
rename from oauth/src/connections/calendly/init.ts
rename to core/oauth/src/connections/calendly/init.ts
diff --git a/oauth/src/connections/calendly/refresh.ts b/core/oauth/src/connections/calendly/refresh.ts
similarity index 100%
rename from oauth/src/connections/calendly/refresh.ts
rename to core/oauth/src/connections/calendly/refresh.ts
diff --git a/oauth/src/connections/canva/init.ts b/core/oauth/src/connections/canva/init.ts
similarity index 100%
rename from oauth/src/connections/canva/init.ts
rename to core/oauth/src/connections/canva/init.ts
diff --git a/oauth/src/connections/canva/refresh.ts b/core/oauth/src/connections/canva/refresh.ts
similarity index 100%
rename from oauth/src/connections/canva/refresh.ts
rename to core/oauth/src/connections/canva/refresh.ts
diff --git a/oauth/src/connections/clover/init.ts b/core/oauth/src/connections/clover/init.ts
similarity index 100%
rename from oauth/src/connections/clover/init.ts
rename to core/oauth/src/connections/clover/init.ts
diff --git a/oauth/src/connections/clover/refresh.ts b/core/oauth/src/connections/clover/refresh.ts
similarity index 100%
rename from oauth/src/connections/clover/refresh.ts
rename to core/oauth/src/connections/clover/refresh.ts
diff --git a/oauth/src/connections/contentstackContentManagement/init.ts b/core/oauth/src/connections/contentstackContentManagement/init.ts
similarity index 100%
rename from oauth/src/connections/contentstackContentManagement/init.ts
rename to core/oauth/src/connections/contentstackContentManagement/init.ts
diff --git a/oauth/src/connections/contentstackContentManagement/refresh.ts b/core/oauth/src/connections/contentstackContentManagement/refresh.ts
similarity index 100%
rename from oauth/src/connections/contentstackContentManagement/refresh.ts
rename to core/oauth/src/connections/contentstackContentManagement/refresh.ts
diff --git a/oauth/src/connections/dropbox/init.ts b/core/oauth/src/connections/dropbox/init.ts
similarity index 100%
rename from oauth/src/connections/dropbox/init.ts
rename to core/oauth/src/connections/dropbox/init.ts
diff --git a/oauth/src/connections/dropbox/refresh.ts b/core/oauth/src/connections/dropbox/refresh.ts
similarity index 100%
rename from oauth/src/connections/dropbox/refresh.ts
rename to core/oauth/src/connections/dropbox/refresh.ts
diff --git a/oauth/src/connections/dynamicDispatch/init.ts b/core/oauth/src/connections/dynamicDispatch/init.ts
similarity index 100%
rename from oauth/src/connections/dynamicDispatch/init.ts
rename to core/oauth/src/connections/dynamicDispatch/init.ts
diff --git a/oauth/src/connections/freshbooks/init.ts b/core/oauth/src/connections/freshbooks/init.ts
similarity index 100%
rename from oauth/src/connections/freshbooks/init.ts
rename to core/oauth/src/connections/freshbooks/init.ts
diff --git a/oauth/src/connections/freshbooks/refresh.ts b/core/oauth/src/connections/freshbooks/refresh.ts
similarity index 100%
rename from oauth/src/connections/freshbooks/refresh.ts
rename to core/oauth/src/connections/freshbooks/refresh.ts
diff --git a/oauth/src/connections/front/init.ts b/core/oauth/src/connections/front/init.ts
similarity index 100%
rename from oauth/src/connections/front/init.ts
rename to core/oauth/src/connections/front/init.ts
diff --git a/oauth/src/connections/front/refresh.ts b/core/oauth/src/connections/front/refresh.ts
similarity index 100%
rename from oauth/src/connections/front/refresh.ts
rename to core/oauth/src/connections/front/refresh.ts
diff --git a/oauth/src/connections/github/init.ts b/core/oauth/src/connections/github/init.ts
similarity index 100%
rename from oauth/src/connections/github/init.ts
rename to core/oauth/src/connections/github/init.ts
diff --git a/oauth/src/connections/github/refresh.ts b/core/oauth/src/connections/github/refresh.ts
similarity index 100%
rename from oauth/src/connections/github/refresh.ts
rename to core/oauth/src/connections/github/refresh.ts
diff --git a/oauth/src/connections/gong/init.ts b/core/oauth/src/connections/gong/init.ts
similarity index 100%
rename from oauth/src/connections/gong/init.ts
rename to core/oauth/src/connections/gong/init.ts
diff --git a/oauth/src/connections/gong/refresh.ts b/core/oauth/src/connections/gong/refresh.ts
similarity index 100%
rename from oauth/src/connections/gong/refresh.ts
rename to core/oauth/src/connections/gong/refresh.ts
diff --git a/oauth/src/connections/google/init.ts b/core/oauth/src/connections/google/init.ts
similarity index 100%
rename from oauth/src/connections/google/init.ts
rename to core/oauth/src/connections/google/init.ts
diff --git a/oauth/src/connections/google/refresh.ts b/core/oauth/src/connections/google/refresh.ts
similarity index 100%
rename from oauth/src/connections/google/refresh.ts
rename to core/oauth/src/connections/google/refresh.ts
diff --git a/oauth/src/connections/hubspot/init.ts b/core/oauth/src/connections/hubspot/init.ts
similarity index 100%
rename from oauth/src/connections/hubspot/init.ts
rename to core/oauth/src/connections/hubspot/init.ts
diff --git a/oauth/src/connections/hubspot/refresh.ts b/core/oauth/src/connections/hubspot/refresh.ts
similarity index 100%
rename from oauth/src/connections/hubspot/refresh.ts
rename to core/oauth/src/connections/hubspot/refresh.ts
diff --git a/oauth/src/connections/intercom/init.ts b/core/oauth/src/connections/intercom/init.ts
similarity index 100%
rename from oauth/src/connections/intercom/init.ts
rename to core/oauth/src/connections/intercom/init.ts
diff --git a/oauth/src/connections/intercom/refresh.ts b/core/oauth/src/connections/intercom/refresh.ts
similarity index 100%
rename from oauth/src/connections/intercom/refresh.ts
rename to core/oauth/src/connections/intercom/refresh.ts
diff --git a/oauth/src/connections/jira/init.ts b/core/oauth/src/connections/jira/init.ts
similarity index 100%
rename from oauth/src/connections/jira/init.ts
rename to core/oauth/src/connections/jira/init.ts
diff --git a/oauth/src/connections/jira/refresh.ts b/core/oauth/src/connections/jira/refresh.ts
similarity index 100%
rename from oauth/src/connections/jira/refresh.ts
rename to core/oauth/src/connections/jira/refresh.ts
diff --git a/oauth/src/connections/linear/init.ts b/core/oauth/src/connections/linear/init.ts
similarity index 100%
rename from oauth/src/connections/linear/init.ts
rename to core/oauth/src/connections/linear/init.ts
diff --git a/oauth/src/connections/linear/refresh.ts b/core/oauth/src/connections/linear/refresh.ts
similarity index 100%
rename from oauth/src/connections/linear/refresh.ts
rename to core/oauth/src/connections/linear/refresh.ts
diff --git a/oauth/src/connections/linkedIn/init.ts b/core/oauth/src/connections/linkedIn/init.ts
similarity index 100%
rename from oauth/src/connections/linkedIn/init.ts
rename to core/oauth/src/connections/linkedIn/init.ts
diff --git a/oauth/src/connections/linkedIn/refresh.ts b/core/oauth/src/connections/linkedIn/refresh.ts
similarity index 100%
rename from oauth/src/connections/linkedIn/refresh.ts
rename to core/oauth/src/connections/linkedIn/refresh.ts
diff --git a/oauth/src/connections/mailchimp/init.ts b/core/oauth/src/connections/mailchimp/init.ts
similarity index 100%
rename from oauth/src/connections/mailchimp/init.ts
rename to core/oauth/src/connections/mailchimp/init.ts
diff --git a/oauth/src/connections/mailchimp/refresh.ts b/core/oauth/src/connections/mailchimp/refresh.ts
similarity index 100%
rename from oauth/src/connections/mailchimp/refresh.ts
rename to core/oauth/src/connections/mailchimp/refresh.ts
diff --git a/oauth/src/connections/microsoftDynamics365BusinessCentral/init.ts b/core/oauth/src/connections/microsoftDynamics365BusinessCentral/init.ts
similarity index 100%
rename from oauth/src/connections/microsoftDynamics365BusinessCentral/init.ts
rename to core/oauth/src/connections/microsoftDynamics365BusinessCentral/init.ts
diff --git a/oauth/src/connections/microsoftDynamics365BusinessCentral/refresh.ts b/core/oauth/src/connections/microsoftDynamics365BusinessCentral/refresh.ts
similarity index 100%
rename from oauth/src/connections/microsoftDynamics365BusinessCentral/refresh.ts
rename to core/oauth/src/connections/microsoftDynamics365BusinessCentral/refresh.ts
diff --git a/oauth/src/connections/microsoftDynamics365Sales/init.ts b/core/oauth/src/connections/microsoftDynamics365Sales/init.ts
similarity index 100%
rename from oauth/src/connections/microsoftDynamics365Sales/init.ts
rename to core/oauth/src/connections/microsoftDynamics365Sales/init.ts
diff --git a/oauth/src/connections/microsoftDynamics365Sales/refresh.ts b/core/oauth/src/connections/microsoftDynamics365Sales/refresh.ts
similarity index 100%
rename from oauth/src/connections/microsoftDynamics365Sales/refresh.ts
rename to core/oauth/src/connections/microsoftDynamics365Sales/refresh.ts
diff --git a/oauth/src/connections/netsuite/init.ts b/core/oauth/src/connections/netsuite/init.ts
similarity index 100%
rename from oauth/src/connections/netsuite/init.ts
rename to core/oauth/src/connections/netsuite/init.ts
diff --git a/oauth/src/connections/netsuite/refresh.ts b/core/oauth/src/connections/netsuite/refresh.ts
similarity index 100%
rename from oauth/src/connections/netsuite/refresh.ts
rename to core/oauth/src/connections/netsuite/refresh.ts
diff --git a/oauth/src/connections/notion/init.ts b/core/oauth/src/connections/notion/init.ts
similarity index 100%
rename from oauth/src/connections/notion/init.ts
rename to core/oauth/src/connections/notion/init.ts
diff --git a/oauth/src/connections/notion/refresh.ts b/core/oauth/src/connections/notion/refresh.ts
similarity index 100%
rename from oauth/src/connections/notion/refresh.ts
rename to core/oauth/src/connections/notion/refresh.ts
diff --git a/oauth/src/connections/oneDrive/init.ts b/core/oauth/src/connections/oneDrive/init.ts
similarity index 100%
rename from oauth/src/connections/oneDrive/init.ts
rename to core/oauth/src/connections/oneDrive/init.ts
diff --git a/oauth/src/connections/oneDrive/refresh.ts b/core/oauth/src/connections/oneDrive/refresh.ts
similarity index 100%
rename from oauth/src/connections/oneDrive/refresh.ts
rename to core/oauth/src/connections/oneDrive/refresh.ts
diff --git a/oauth/src/connections/outlookCalendar/init.ts b/core/oauth/src/connections/outlookCalendar/init.ts
similarity index 100%
rename from oauth/src/connections/outlookCalendar/init.ts
rename to core/oauth/src/connections/outlookCalendar/init.ts
diff --git a/oauth/src/connections/outlookCalendar/refresh.ts b/core/oauth/src/connections/outlookCalendar/refresh.ts
similarity index 100%
rename from oauth/src/connections/outlookCalendar/refresh.ts
rename to core/oauth/src/connections/outlookCalendar/refresh.ts
diff --git a/oauth/src/connections/outlookMail/init.ts b/core/oauth/src/connections/outlookMail/init.ts
similarity index 100%
rename from oauth/src/connections/outlookMail/init.ts
rename to core/oauth/src/connections/outlookMail/init.ts
diff --git a/oauth/src/connections/outlookMail/refresh.ts b/core/oauth/src/connections/outlookMail/refresh.ts
similarity index 100%
rename from oauth/src/connections/outlookMail/refresh.ts
rename to core/oauth/src/connections/outlookMail/refresh.ts
diff --git a/oauth/src/connections/pipedrive/init.ts b/core/oauth/src/connections/pipedrive/init.ts
similarity index 100%
rename from oauth/src/connections/pipedrive/init.ts
rename to core/oauth/src/connections/pipedrive/init.ts
diff --git a/oauth/src/connections/pipedrive/refresh.ts b/core/oauth/src/connections/pipedrive/refresh.ts
similarity index 100%
rename from oauth/src/connections/pipedrive/refresh.ts
rename to core/oauth/src/connections/pipedrive/refresh.ts
diff --git a/oauth/src/connections/puzzleIo/init.ts b/core/oauth/src/connections/puzzleIo/init.ts
similarity index 100%
rename from oauth/src/connections/puzzleIo/init.ts
rename to core/oauth/src/connections/puzzleIo/init.ts
diff --git a/oauth/src/connections/puzzleIo/refresh.ts b/core/oauth/src/connections/puzzleIo/refresh.ts
similarity index 100%
rename from oauth/src/connections/puzzleIo/refresh.ts
rename to core/oauth/src/connections/puzzleIo/refresh.ts
diff --git a/oauth/src/connections/quickbooks/init.ts b/core/oauth/src/connections/quickbooks/init.ts
similarity index 100%
rename from oauth/src/connections/quickbooks/init.ts
rename to core/oauth/src/connections/quickbooks/init.ts
diff --git a/oauth/src/connections/quickbooks/refresh.ts b/core/oauth/src/connections/quickbooks/refresh.ts
similarity index 100%
rename from oauth/src/connections/quickbooks/refresh.ts
rename to core/oauth/src/connections/quickbooks/refresh.ts
diff --git a/oauth/src/connections/sageAccounting/init.ts b/core/oauth/src/connections/sageAccounting/init.ts
similarity index 100%
rename from oauth/src/connections/sageAccounting/init.ts
rename to core/oauth/src/connections/sageAccounting/init.ts
diff --git a/oauth/src/connections/sageAccounting/refresh.ts b/core/oauth/src/connections/sageAccounting/refresh.ts
similarity index 100%
rename from oauth/src/connections/sageAccounting/refresh.ts
rename to core/oauth/src/connections/sageAccounting/refresh.ts
diff --git a/oauth/src/connections/salesforce/init.ts b/core/oauth/src/connections/salesforce/init.ts
similarity index 100%
rename from oauth/src/connections/salesforce/init.ts
rename to core/oauth/src/connections/salesforce/init.ts
diff --git a/oauth/src/connections/salesforce/refresh.ts b/core/oauth/src/connections/salesforce/refresh.ts
similarity index 100%
rename from oauth/src/connections/salesforce/refresh.ts
rename to core/oauth/src/connections/salesforce/refresh.ts
diff --git a/oauth/src/connections/shareFile/init.ts b/core/oauth/src/connections/shareFile/init.ts
similarity index 100%
rename from oauth/src/connections/shareFile/init.ts
rename to core/oauth/src/connections/shareFile/init.ts
diff --git a/oauth/src/connections/shareFile/refresh.ts b/core/oauth/src/connections/shareFile/refresh.ts
similarity index 100%
rename from oauth/src/connections/shareFile/refresh.ts
rename to core/oauth/src/connections/shareFile/refresh.ts
diff --git a/oauth/src/connections/sharePoint/init.ts b/core/oauth/src/connections/sharePoint/init.ts
similarity index 100%
rename from oauth/src/connections/sharePoint/init.ts
rename to core/oauth/src/connections/sharePoint/init.ts
diff --git a/oauth/src/connections/sharePoint/refresh.ts b/core/oauth/src/connections/sharePoint/refresh.ts
similarity index 100%
rename from oauth/src/connections/sharePoint/refresh.ts
rename to core/oauth/src/connections/sharePoint/refresh.ts
diff --git a/oauth/src/connections/shipBob/init.ts b/core/oauth/src/connections/shipBob/init.ts
similarity index 100%
rename from oauth/src/connections/shipBob/init.ts
rename to core/oauth/src/connections/shipBob/init.ts
diff --git a/oauth/src/connections/shipBob/refresh.ts b/core/oauth/src/connections/shipBob/refresh.ts
similarity index 100%
rename from oauth/src/connections/shipBob/refresh.ts
rename to core/oauth/src/connections/shipBob/refresh.ts
diff --git a/oauth/src/connections/slack/init.ts b/core/oauth/src/connections/slack/init.ts
similarity index 100%
rename from oauth/src/connections/slack/init.ts
rename to core/oauth/src/connections/slack/init.ts
diff --git a/oauth/src/connections/slack/refresh.ts b/core/oauth/src/connections/slack/refresh.ts
similarity index 100%
rename from oauth/src/connections/slack/refresh.ts
rename to core/oauth/src/connections/slack/refresh.ts
diff --git a/oauth/src/connections/square/init.ts b/core/oauth/src/connections/square/init.ts
similarity index 100%
rename from oauth/src/connections/square/init.ts
rename to core/oauth/src/connections/square/init.ts
diff --git a/oauth/src/connections/square/refresh.ts b/core/oauth/src/connections/square/refresh.ts
similarity index 100%
rename from oauth/src/connections/square/refresh.ts
rename to core/oauth/src/connections/square/refresh.ts
diff --git a/oauth/src/connections/supabase/init.ts b/core/oauth/src/connections/supabase/init.ts
similarity index 100%
rename from oauth/src/connections/supabase/init.ts
rename to core/oauth/src/connections/supabase/init.ts
diff --git a/oauth/src/connections/supabase/refresh.ts b/core/oauth/src/connections/supabase/refresh.ts
similarity index 100%
rename from oauth/src/connections/supabase/refresh.ts
rename to core/oauth/src/connections/supabase/refresh.ts
diff --git a/oauth/src/connections/teams/init.ts b/core/oauth/src/connections/teams/init.ts
similarity index 100%
rename from oauth/src/connections/teams/init.ts
rename to core/oauth/src/connections/teams/init.ts
diff --git a/oauth/src/connections/teams/refresh.ts b/core/oauth/src/connections/teams/refresh.ts
similarity index 100%
rename from oauth/src/connections/teams/refresh.ts
rename to core/oauth/src/connections/teams/refresh.ts
diff --git a/oauth/src/connections/todoist/init.ts b/core/oauth/src/connections/todoist/init.ts
similarity index 100%
rename from oauth/src/connections/todoist/init.ts
rename to core/oauth/src/connections/todoist/init.ts
diff --git a/oauth/src/connections/todoist/refresh.ts b/core/oauth/src/connections/todoist/refresh.ts
similarity index 100%
rename from oauth/src/connections/todoist/refresh.ts
rename to core/oauth/src/connections/todoist/refresh.ts
diff --git a/oauth/src/connections/typeform/init.ts b/core/oauth/src/connections/typeform/init.ts
similarity index 100%
rename from oauth/src/connections/typeform/init.ts
rename to core/oauth/src/connections/typeform/init.ts
diff --git a/oauth/src/connections/typeform/refresh.ts b/core/oauth/src/connections/typeform/refresh.ts
similarity index 100%
rename from oauth/src/connections/typeform/refresh.ts
rename to core/oauth/src/connections/typeform/refresh.ts
diff --git a/oauth/src/connections/webflow/init.ts b/core/oauth/src/connections/webflow/init.ts
similarity index 100%
rename from oauth/src/connections/webflow/init.ts
rename to core/oauth/src/connections/webflow/init.ts
diff --git a/oauth/src/connections/webflow/refresh.ts b/core/oauth/src/connections/webflow/refresh.ts
similarity index 100%
rename from oauth/src/connections/webflow/refresh.ts
rename to core/oauth/src/connections/webflow/refresh.ts
diff --git a/oauth/src/connections/wikimedia/init.ts b/core/oauth/src/connections/wikimedia/init.ts
similarity index 100%
rename from oauth/src/connections/wikimedia/init.ts
rename to core/oauth/src/connections/wikimedia/init.ts
diff --git a/oauth/src/connections/wikimedia/refresh.ts b/core/oauth/src/connections/wikimedia/refresh.ts
similarity index 100%
rename from oauth/src/connections/wikimedia/refresh.ts
rename to core/oauth/src/connections/wikimedia/refresh.ts
diff --git a/oauth/src/connections/wordPress/init.ts b/core/oauth/src/connections/wordPress/init.ts
similarity index 100%
rename from oauth/src/connections/wordPress/init.ts
rename to core/oauth/src/connections/wordPress/init.ts
diff --git a/oauth/src/connections/wordPress/refresh.ts b/core/oauth/src/connections/wordPress/refresh.ts
similarity index 100%
rename from oauth/src/connections/wordPress/refresh.ts
rename to core/oauth/src/connections/wordPress/refresh.ts
diff --git a/oauth/src/connections/x/init.ts b/core/oauth/src/connections/x/init.ts
similarity index 100%
rename from oauth/src/connections/x/init.ts
rename to core/oauth/src/connections/x/init.ts
diff --git a/oauth/src/connections/x/refresh.ts b/core/oauth/src/connections/x/refresh.ts
similarity index 100%
rename from oauth/src/connections/x/refresh.ts
rename to core/oauth/src/connections/x/refresh.ts
diff --git a/oauth/src/connections/xero/init.ts b/core/oauth/src/connections/xero/init.ts
similarity index 100%
rename from oauth/src/connections/xero/init.ts
rename to core/oauth/src/connections/xero/init.ts
diff --git a/oauth/src/connections/xero/refresh.ts b/core/oauth/src/connections/xero/refresh.ts
similarity index 100%
rename from oauth/src/connections/xero/refresh.ts
rename to core/oauth/src/connections/xero/refresh.ts
diff --git a/oauth/src/connections/zendesk/init.ts b/core/oauth/src/connections/zendesk/init.ts
similarity index 100%
rename from oauth/src/connections/zendesk/init.ts
rename to core/oauth/src/connections/zendesk/init.ts
diff --git a/oauth/src/connections/zendesk/refresh.ts b/core/oauth/src/connections/zendesk/refresh.ts
similarity index 100%
rename from oauth/src/connections/zendesk/refresh.ts
rename to core/oauth/src/connections/zendesk/refresh.ts
diff --git a/oauth/src/connections/zoho/init.ts b/core/oauth/src/connections/zoho/init.ts
similarity index 100%
rename from oauth/src/connections/zoho/init.ts
rename to core/oauth/src/connections/zoho/init.ts
diff --git a/oauth/src/connections/zoho/refresh.ts b/core/oauth/src/connections/zoho/refresh.ts
similarity index 100%
rename from oauth/src/connections/zoho/refresh.ts
rename to core/oauth/src/connections/zoho/refresh.ts
diff --git a/oauth/src/connections/zoom/init.ts b/core/oauth/src/connections/zoom/init.ts
similarity index 100%
rename from oauth/src/connections/zoom/init.ts
rename to core/oauth/src/connections/zoom/init.ts
diff --git a/oauth/src/connections/zoom/refresh.ts b/core/oauth/src/connections/zoom/refresh.ts
similarity index 100%
rename from oauth/src/connections/zoom/refresh.ts
rename to core/oauth/src/connections/zoom/refresh.ts
diff --git a/oauth/src/index.ts b/core/oauth/src/index.ts
similarity index 100%
rename from oauth/src/index.ts
rename to core/oauth/src/index.ts
diff --git a/oauth/src/lib/helpers.ts b/core/oauth/src/lib/helpers.ts
similarity index 100%
rename from oauth/src/lib/helpers.ts
rename to core/oauth/src/lib/helpers.ts
diff --git a/oauth/src/lib/types.ts b/core/oauth/src/lib/types.ts
similarity index 100%
rename from oauth/src/lib/types.ts
rename to core/oauth/src/lib/types.ts
diff --git a/oauth/tsconfig.json b/core/oauth/tsconfig.json
similarity index 100%
rename from oauth/tsconfig.json
rename to core/oauth/tsconfig.json
diff --git a/osentities/.gitignore b/core/osentities/.gitignore
similarity index 100%
rename from osentities/.gitignore
rename to core/osentities/.gitignore
diff --git a/osentities/Cargo.toml b/core/osentities/Cargo.toml
similarity index 100%
rename from osentities/Cargo.toml
rename to core/osentities/Cargo.toml
diff --git a/osentities/README.md b/core/osentities/README.md
similarity index 100%
rename from osentities/README.md
rename to core/osentities/README.md
diff --git a/osentities/src/algebra/crypto.rs b/core/osentities/src/algebra/crypto.rs
similarity index 100%
rename from osentities/src/algebra/crypto.rs
rename to core/osentities/src/algebra/crypto.rs
diff --git a/osentities/src/algebra/hash.rs b/core/osentities/src/algebra/hash.rs
similarity index 100%
rename from osentities/src/algebra/hash.rs
rename to core/osentities/src/algebra/hash.rs
diff --git a/osentities/src/algebra/json.rs b/core/osentities/src/algebra/json.rs
similarity index 100%
rename from osentities/src/algebra/json.rs
rename to core/osentities/src/algebra/json.rs
diff --git a/osentities/src/algebra/mod.rs b/core/osentities/src/algebra/mod.rs
similarity index 100%
rename from osentities/src/algebra/mod.rs
rename to core/osentities/src/algebra/mod.rs
diff --git a/osentities/src/algebra/oauth.rs b/core/osentities/src/algebra/oauth.rs
similarity index 100%
rename from osentities/src/algebra/oauth.rs
rename to core/osentities/src/algebra/oauth.rs
diff --git a/osentities/src/algebra/pipeline.rs b/core/osentities/src/algebra/pipeline.rs
similarity index 100%
rename from osentities/src/algebra/pipeline.rs
rename to core/osentities/src/algebra/pipeline.rs
diff --git a/osentities/src/algebra/secret.rs b/core/osentities/src/algebra/secret.rs
similarity index 100%
rename from osentities/src/algebra/secret.rs
rename to core/osentities/src/algebra/secret.rs
diff --git a/osentities/src/algebra/store.rs b/core/osentities/src/algebra/store.rs
similarity index 100%
rename from osentities/src/algebra/store.rs
rename to core/osentities/src/algebra/store.rs
diff --git a/osentities/src/algebra/string.rs b/core/osentities/src/algebra/string.rs
similarity index 100%
rename from osentities/src/algebra/string.rs
rename to core/osentities/src/algebra/string.rs
diff --git a/osentities/src/algebra/template.rs b/core/osentities/src/algebra/template.rs
similarity index 100%
rename from osentities/src/algebra/template.rs
rename to core/osentities/src/algebra/template.rs
diff --git a/osentities/src/algebra/timed.rs b/core/osentities/src/algebra/timed.rs
similarity index 100%
rename from osentities/src/algebra/timed.rs
rename to core/osentities/src/algebra/timed.rs
diff --git a/osentities/src/domain/access_key/access_key_data.rs b/core/osentities/src/domain/access_key/access_key_data.rs
similarity index 100%
rename from osentities/src/domain/access_key/access_key_data.rs
rename to core/osentities/src/domain/access_key/access_key_data.rs
diff --git a/osentities/src/domain/access_key/access_key_prefix.rs b/core/osentities/src/domain/access_key/access_key_prefix.rs
similarity index 100%
rename from osentities/src/domain/access_key/access_key_prefix.rs
rename to core/osentities/src/domain/access_key/access_key_prefix.rs
diff --git a/osentities/src/domain/access_key/encrypted_access_key.rs b/core/osentities/src/domain/access_key/encrypted_access_key.rs
similarity index 100%
rename from osentities/src/domain/access_key/encrypted_access_key.rs
rename to core/osentities/src/domain/access_key/encrypted_access_key.rs
diff --git a/osentities/src/domain/access_key/encrypted_data.rs b/core/osentities/src/domain/access_key/encrypted_data.rs
similarity index 100%
rename from osentities/src/domain/access_key/encrypted_data.rs
rename to core/osentities/src/domain/access_key/encrypted_data.rs
diff --git a/osentities/src/domain/access_key/event_type.rs b/core/osentities/src/domain/access_key/event_type.rs
similarity index 100%
rename from osentities/src/domain/access_key/event_type.rs
rename to core/osentities/src/domain/access_key/event_type.rs
diff --git a/osentities/src/domain/access_key/mod.rs b/core/osentities/src/domain/access_key/mod.rs
similarity index 100%
rename from osentities/src/domain/access_key/mod.rs
rename to core/osentities/src/domain/access_key/mod.rs
diff --git a/osentities/src/domain/configuration/cache.rs b/core/osentities/src/domain/configuration/cache.rs
similarity index 100%
rename from osentities/src/domain/configuration/cache.rs
rename to core/osentities/src/domain/configuration/cache.rs
diff --git a/osentities/src/domain/configuration/database.rs b/core/osentities/src/domain/configuration/database.rs
similarity index 100%
rename from osentities/src/domain/configuration/database.rs
rename to core/osentities/src/domain/configuration/database.rs
diff --git a/osentities/src/domain/configuration/environment.rs b/core/osentities/src/domain/configuration/environment.rs
similarity index 100%
rename from osentities/src/domain/configuration/environment.rs
rename to core/osentities/src/domain/configuration/environment.rs
diff --git a/osentities/src/domain/configuration/mod.rs b/core/osentities/src/domain/configuration/mod.rs
similarity index 100%
rename from osentities/src/domain/configuration/mod.rs
rename to core/osentities/src/domain/configuration/mod.rs
diff --git a/osentities/src/domain/configuration/secrets.rs b/core/osentities/src/domain/configuration/secrets.rs
similarity index 100%
rename from osentities/src/domain/configuration/secrets.rs
rename to core/osentities/src/domain/configuration/secrets.rs
diff --git a/osentities/src/domain/connection/api_model_config.rs b/core/osentities/src/domain/connection/api_model_config.rs
similarity index 100%
rename from osentities/src/domain/connection/api_model_config.rs
rename to core/osentities/src/domain/connection/api_model_config.rs
diff --git a/osentities/src/domain/connection/connection_definition.rs b/core/osentities/src/domain/connection/connection_definition.rs
similarity index 100%
rename from osentities/src/domain/connection/connection_definition.rs
rename to core/osentities/src/domain/connection/connection_definition.rs
diff --git a/osentities/src/domain/connection/connection_model_definition.rs b/core/osentities/src/domain/connection/connection_model_definition.rs
similarity index 100%
rename from osentities/src/domain/connection/connection_model_definition.rs
rename to core/osentities/src/domain/connection/connection_model_definition.rs
diff --git a/osentities/src/domain/connection/connection_model_schema.rs b/core/osentities/src/domain/connection/connection_model_schema.rs
similarity index 100%
rename from osentities/src/domain/connection/connection_model_schema.rs
rename to core/osentities/src/domain/connection/connection_model_schema.rs
diff --git a/osentities/src/domain/connection/connection_oauth_definition.rs b/core/osentities/src/domain/connection/connection_oauth_definition.rs
similarity index 100%
rename from osentities/src/domain/connection/connection_oauth_definition.rs
rename to core/osentities/src/domain/connection/connection_oauth_definition.rs
diff --git a/osentities/src/domain/connection/mod.rs b/core/osentities/src/domain/connection/mod.rs
similarity index 100%
rename from osentities/src/domain/connection/mod.rs
rename to core/osentities/src/domain/connection/mod.rs
diff --git a/osentities/src/domain/constant/mod.rs b/core/osentities/src/domain/constant/mod.rs
similarity index 100%
rename from osentities/src/domain/constant/mod.rs
rename to core/osentities/src/domain/constant/mod.rs
diff --git a/osentities/src/domain/error/axum_error.rs b/core/osentities/src/domain/error/axum_error.rs
similarity index 100%
rename from osentities/src/domain/error/axum_error.rs
rename to core/osentities/src/domain/error/axum_error.rs
diff --git a/osentities/src/domain/error/mod.rs b/core/osentities/src/domain/error/mod.rs
similarity index 100%
rename from osentities/src/domain/error/mod.rs
rename to core/osentities/src/domain/error/mod.rs
diff --git a/osentities/src/domain/event/emitted_events.rs b/core/osentities/src/domain/event/emitted_events.rs
similarity index 100%
rename from osentities/src/domain/event/emitted_events.rs
rename to core/osentities/src/domain/event/emitted_events.rs
diff --git a/osentities/src/domain/event/event_access.rs b/core/osentities/src/domain/event/event_access.rs
similarity index 100%
rename from osentities/src/domain/event/event_access.rs
rename to core/osentities/src/domain/event/event_access.rs
diff --git a/osentities/src/domain/event/event_state.rs b/core/osentities/src/domain/event/event_state.rs
similarity index 100%
rename from osentities/src/domain/event/event_state.rs
rename to core/osentities/src/domain/event/event_state.rs
diff --git a/osentities/src/domain/event/hashes.rs b/core/osentities/src/domain/event/hashes.rs
similarity index 100%
rename from osentities/src/domain/event/hashes.rs
rename to core/osentities/src/domain/event/hashes.rs
diff --git a/osentities/src/domain/event/mod.rs b/core/osentities/src/domain/event/mod.rs
similarity index 100%
rename from osentities/src/domain/event/mod.rs
rename to core/osentities/src/domain/event/mod.rs
diff --git a/osentities/src/domain/event/task.rs b/core/osentities/src/domain/event/task.rs
similarity index 100%
rename from osentities/src/domain/event/task.rs
rename to core/osentities/src/domain/event/task.rs
diff --git a/osentities/src/domain/http/mod.rs b/core/osentities/src/domain/http/mod.rs
similarity index 100%
rename from osentities/src/domain/http/mod.rs
rename to core/osentities/src/domain/http/mod.rs
diff --git a/osentities/src/domain/id/mod.rs b/core/osentities/src/domain/id/mod.rs
similarity index 100%
rename from osentities/src/domain/id/mod.rs
rename to core/osentities/src/domain/id/mod.rs
diff --git a/osentities/src/domain/id/prefix.rs b/core/osentities/src/domain/id/prefix.rs
similarity index 100%
rename from osentities/src/domain/id/prefix.rs
rename to core/osentities/src/domain/id/prefix.rs
diff --git a/osentities/src/domain/mod.rs b/core/osentities/src/domain/mod.rs
similarity index 100%
rename from osentities/src/domain/mod.rs
rename to core/osentities/src/domain/mod.rs
diff --git a/osentities/src/domain/pipeline/destination.rs b/core/osentities/src/domain/pipeline/destination.rs
similarity index 100%
rename from osentities/src/domain/pipeline/destination.rs
rename to core/osentities/src/domain/pipeline/destination.rs
diff --git a/osentities/src/domain/pipeline/mod.rs b/core/osentities/src/domain/pipeline/mod.rs
similarity index 100%
rename from osentities/src/domain/pipeline/mod.rs
rename to core/osentities/src/domain/pipeline/mod.rs
diff --git a/osentities/src/domain/platform/mod.rs b/core/osentities/src/domain/platform/mod.rs
similarity index 100%
rename from osentities/src/domain/platform/mod.rs
rename to core/osentities/src/domain/platform/mod.rs
diff --git a/osentities/src/domain/platform/page.rs b/core/osentities/src/domain/platform/page.rs
similarity index 100%
rename from osentities/src/domain/platform/page.rs
rename to core/osentities/src/domain/platform/page.rs
diff --git a/osentities/src/domain/platform/type.rs b/core/osentities/src/domain/platform/type.rs
similarity index 100%
rename from osentities/src/domain/platform/type.rs
rename to core/osentities/src/domain/platform/type.rs
diff --git a/osentities/src/domain/schema/common_model.rs b/core/osentities/src/domain/schema/common_model.rs
similarity index 100%
rename from osentities/src/domain/schema/common_model.rs
rename to core/osentities/src/domain/schema/common_model.rs
diff --git a/osentities/src/domain/schema/json_mapper.rs b/core/osentities/src/domain/schema/json_mapper.rs
similarity index 100%
rename from osentities/src/domain/schema/json_mapper.rs
rename to core/osentities/src/domain/schema/json_mapper.rs
diff --git a/osentities/src/domain/schema/json_schema.rs b/core/osentities/src/domain/schema/json_schema.rs
similarity index 100%
rename from osentities/src/domain/schema/json_schema.rs
rename to core/osentities/src/domain/schema/json_schema.rs
diff --git a/osentities/src/domain/schema/mod.rs b/core/osentities/src/domain/schema/mod.rs
similarity index 100%
rename from osentities/src/domain/schema/mod.rs
rename to core/osentities/src/domain/schema/mod.rs
diff --git a/osentities/src/domain/secret/database_secret.rs b/core/osentities/src/domain/secret/database_secret.rs
similarity index 100%
rename from osentities/src/domain/secret/database_secret.rs
rename to core/osentities/src/domain/secret/database_secret.rs
diff --git a/osentities/src/domain/secret/hashed_secret.rs b/core/osentities/src/domain/secret/hashed_secret.rs
similarity index 100%
rename from osentities/src/domain/secret/hashed_secret.rs
rename to core/osentities/src/domain/secret/hashed_secret.rs
diff --git a/osentities/src/domain/secret/mod.rs b/core/osentities/src/domain/secret/mod.rs
similarity index 100%
rename from osentities/src/domain/secret/mod.rs
rename to core/osentities/src/domain/secret/mod.rs
diff --git a/osentities/src/domain/secret/oauth_secret.rs b/core/osentities/src/domain/secret/oauth_secret.rs
similarity index 100%
rename from osentities/src/domain/secret/oauth_secret.rs
rename to core/osentities/src/domain/secret/oauth_secret.rs
diff --git a/osentities/src/domain/shared/mod.rs b/core/osentities/src/domain/shared/mod.rs
similarity index 100%
rename from osentities/src/domain/shared/mod.rs
rename to core/osentities/src/domain/shared/mod.rs
diff --git a/osentities/src/domain/shared/ownership.rs b/core/osentities/src/domain/shared/ownership.rs
similarity index 100%
rename from osentities/src/domain/shared/ownership.rs
rename to core/osentities/src/domain/shared/ownership.rs
diff --git a/osentities/src/domain/shared/record_metadata.rs b/core/osentities/src/domain/shared/record_metadata.rs
similarity index 100%
rename from osentities/src/domain/shared/record_metadata.rs
rename to core/osentities/src/domain/shared/record_metadata.rs
diff --git a/osentities/src/domain/shared/settings.rs b/core/osentities/src/domain/shared/settings.rs
similarity index 100%
rename from osentities/src/domain/shared/settings.rs
rename to core/osentities/src/domain/shared/settings.rs
diff --git a/osentities/src/domain/store/mod.rs b/core/osentities/src/domain/store/mod.rs
similarity index 100%
rename from osentities/src/domain/store/mod.rs
rename to core/osentities/src/domain/store/mod.rs
diff --git a/osentities/src/domain/token/mod.rs b/core/osentities/src/domain/token/mod.rs
similarity index 100%
rename from osentities/src/domain/token/mod.rs
rename to core/osentities/src/domain/token/mod.rs
diff --git a/osentities/src/domain/user/mod.rs b/core/osentities/src/domain/user/mod.rs
similarity index 100%
rename from osentities/src/domain/user/mod.rs
rename to core/osentities/src/domain/user/mod.rs
diff --git a/osentities/src/lib.rs b/core/osentities/src/lib.rs
similarity index 100%
rename from osentities/src/lib.rs
rename to core/osentities/src/lib.rs
diff --git a/osentities/src/service/mod.rs b/core/osentities/src/service/mod.rs
similarity index 100%
rename from osentities/src/service/mod.rs
rename to core/osentities/src/service/mod.rs
diff --git a/osentities/src/service/telemetry/mod.rs b/core/osentities/src/service/telemetry/mod.rs
similarity index 100%
rename from osentities/src/service/telemetry/mod.rs
rename to core/osentities/src/service/telemetry/mod.rs
diff --git a/resources/Dockerfile b/core/resources/Dockerfile
similarity index 100%
rename from resources/Dockerfile
rename to core/resources/Dockerfile
diff --git a/resources/images/banner.svg b/core/resources/images/banner.svg
similarity index 100%
rename from resources/images/banner.svg
rename to core/resources/images/banner.svg
diff --git a/resources/seed/clients.bson b/core/resources/seed/clients.bson
similarity index 100%
rename from resources/seed/clients.bson
rename to core/resources/seed/clients.bson
diff --git a/resources/seed/clients.metadata.json b/core/resources/seed/clients.metadata.json
similarity index 100%
rename from resources/seed/clients.metadata.json
rename to core/resources/seed/clients.metadata.json
diff --git a/resources/seed/common-enums.bson b/core/resources/seed/common-enums.bson
similarity index 100%
rename from resources/seed/common-enums.bson
rename to core/resources/seed/common-enums.bson
diff --git a/resources/seed/common-enums.metadata.json b/core/resources/seed/common-enums.metadata.json
similarity index 100%
rename from resources/seed/common-enums.metadata.json
rename to core/resources/seed/common-enums.metadata.json
diff --git a/resources/seed/common-models.bson b/core/resources/seed/common-models.bson
similarity index 100%
rename from resources/seed/common-models.bson
rename to core/resources/seed/common-models.bson
diff --git a/resources/seed/common-models.metadata.json b/core/resources/seed/common-models.metadata.json
similarity index 100%
rename from resources/seed/common-models.metadata.json
rename to core/resources/seed/common-models.metadata.json
diff --git a/resources/seed/connection-definitions.bson b/core/resources/seed/connection-definitions.bson
similarity index 100%
rename from resources/seed/connection-definitions.bson
rename to core/resources/seed/connection-definitions.bson
diff --git a/resources/seed/connection-definitions.metadata.json b/core/resources/seed/connection-definitions.metadata.json
similarity index 100%
rename from resources/seed/connection-definitions.metadata.json
rename to core/resources/seed/connection-definitions.metadata.json
diff --git a/resources/seed/connection-model-definitions.bson b/core/resources/seed/connection-model-definitions.bson
similarity index 100%
rename from resources/seed/connection-model-definitions.bson
rename to core/resources/seed/connection-model-definitions.bson
diff --git a/resources/seed/connection-model-definitions.metadata.json b/core/resources/seed/connection-model-definitions.metadata.json
similarity index 100%
rename from resources/seed/connection-model-definitions.metadata.json
rename to core/resources/seed/connection-model-definitions.metadata.json
diff --git a/resources/seed/connection-model-schema.bson b/core/resources/seed/connection-model-schema.bson
similarity index 100%
rename from resources/seed/connection-model-schema.bson
rename to core/resources/seed/connection-model-schema.bson
diff --git a/resources/seed/connection-model-schema.metadata.json b/core/resources/seed/connection-model-schema.metadata.json
similarity index 100%
rename from resources/seed/connection-model-schema.metadata.json
rename to core/resources/seed/connection-model-schema.metadata.json
diff --git a/resources/seed/connection-oauth-definitions.bson b/core/resources/seed/connection-oauth-definitions.bson
similarity index 100%
rename from resources/seed/connection-oauth-definitions.bson
rename to core/resources/seed/connection-oauth-definitions.bson
diff --git a/resources/seed/connection-oauth-definitions.metadata.json b/core/resources/seed/connection-oauth-definitions.metadata.json
similarity index 100%
rename from resources/seed/connection-oauth-definitions.metadata.json
rename to core/resources/seed/connection-oauth-definitions.metadata.json
diff --git a/resources/seed/connections.bson b/core/resources/seed/connections.bson
similarity index 100%
rename from resources/seed/connections.bson
rename to core/resources/seed/connections.bson
diff --git a/resources/seed/connections.metadata.json b/core/resources/seed/connections.metadata.json
similarity index 100%
rename from resources/seed/connections.metadata.json
rename to core/resources/seed/connections.metadata.json
diff --git a/resources/seed/embed-tokens.bson b/core/resources/seed/embed-tokens.bson
similarity index 100%
rename from resources/seed/embed-tokens.bson
rename to core/resources/seed/embed-tokens.bson
diff --git a/resources/seed/embed-tokens.metadata.json b/core/resources/seed/embed-tokens.metadata.json
similarity index 100%
rename from resources/seed/embed-tokens.metadata.json
rename to core/resources/seed/embed-tokens.metadata.json
diff --git a/resources/seed/event-access.bson b/core/resources/seed/event-access.bson
similarity index 100%
rename from resources/seed/event-access.bson
rename to core/resources/seed/event-access.bson
diff --git a/resources/seed/event-access.metadata.json b/core/resources/seed/event-access.metadata.json
similarity index 100%
rename from resources/seed/event-access.metadata.json
rename to core/resources/seed/event-access.metadata.json
diff --git a/resources/seed/external-events.bson b/core/resources/seed/external-events.bson
similarity index 100%
rename from resources/seed/external-events.bson
rename to core/resources/seed/external-events.bson
diff --git a/resources/seed/external-events.metadata.json b/core/resources/seed/external-events.metadata.json
similarity index 100%
rename from resources/seed/external-events.metadata.json
rename to core/resources/seed/external-events.metadata.json
diff --git a/resources/seed/jobs.bson b/core/resources/seed/jobs.bson
similarity index 100%
rename from resources/seed/jobs.bson
rename to core/resources/seed/jobs.bson
diff --git a/resources/seed/jobs.metadata.json b/core/resources/seed/jobs.metadata.json
similarity index 100%
rename from resources/seed/jobs.metadata.json
rename to core/resources/seed/jobs.metadata.json
diff --git a/resources/seed/platform-pages.bson b/core/resources/seed/platform-pages.bson
similarity index 100%
rename from resources/seed/platform-pages.bson
rename to core/resources/seed/platform-pages.bson
diff --git a/resources/seed/platform-pages.metadata.json b/core/resources/seed/platform-pages.metadata.json
similarity index 100%
rename from resources/seed/platform-pages.metadata.json
rename to core/resources/seed/platform-pages.metadata.json
diff --git a/resources/seed/platforms.bson b/core/resources/seed/platforms.bson
similarity index 100%
rename from resources/seed/platforms.bson
rename to core/resources/seed/platforms.bson
diff --git a/resources/seed/platforms.metadata.json b/core/resources/seed/platforms.metadata.json
similarity index 100%
rename from resources/seed/platforms.metadata.json
rename to core/resources/seed/platforms.metadata.json
diff --git a/resources/seed/secrets.bson b/core/resources/seed/secrets.bson
similarity index 100%
rename from resources/seed/secrets.bson
rename to core/resources/seed/secrets.bson
diff --git a/resources/seed/secrets.metadata.json b/core/resources/seed/secrets.metadata.json
similarity index 100%
rename from resources/seed/secrets.metadata.json
rename to core/resources/seed/secrets.metadata.json
diff --git a/resources/seed/sessions.bson b/core/resources/seed/sessions.bson
similarity index 100%
rename from resources/seed/sessions.bson
rename to core/resources/seed/sessions.bson
diff --git a/resources/seed/sessions.metadata.json b/core/resources/seed/sessions.metadata.json
similarity index 100%
rename from resources/seed/sessions.metadata.json
rename to core/resources/seed/sessions.metadata.json
diff --git a/resources/seed/settings.bson b/core/resources/seed/settings.bson
similarity index 100%
rename from resources/seed/settings.bson
rename to core/resources/seed/settings.bson
diff --git a/resources/seed/settings.metadata.json b/core/resources/seed/settings.metadata.json
similarity index 100%
rename from resources/seed/settings.metadata.json
rename to core/resources/seed/settings.metadata.json
diff --git a/resources/seed/stages.bson b/core/resources/seed/stages.bson
similarity index 100%
rename from resources/seed/stages.bson
rename to core/resources/seed/stages.bson
diff --git a/resources/seed/stages.metadata.json b/core/resources/seed/stages.metadata.json
similarity index 100%
rename from resources/seed/stages.metadata.json
rename to core/resources/seed/stages.metadata.json
diff --git a/resources/seed/system-stats.bson b/core/resources/seed/system-stats.bson
similarity index 100%
rename from resources/seed/system-stats.bson
rename to core/resources/seed/system-stats.bson
diff --git a/resources/seed/system-stats.metadata.json b/core/resources/seed/system-stats.metadata.json
similarity index 100%
rename from resources/seed/system-stats.metadata.json
rename to core/resources/seed/system-stats.metadata.json
diff --git a/resources/seed/users.bson b/core/resources/seed/users.bson
similarity index 100%
rename from resources/seed/users.bson
rename to core/resources/seed/users.bson
diff --git a/resources/seed/users.metadata.json b/core/resources/seed/users.metadata.json
similarity index 100%
rename from resources/seed/users.metadata.json
rename to core/resources/seed/users.metadata.json
diff --git a/unified/Cargo.toml b/core/unified/Cargo.toml
similarity index 100%
rename from unified/Cargo.toml
rename to core/unified/Cargo.toml
diff --git a/unified/README.md b/core/unified/README.md
similarity index 100%
rename from unified/README.md
rename to core/unified/README.md
diff --git a/unified/src/algebra/jsruntime.rs b/core/unified/src/algebra/jsruntime.rs
similarity index 100%
rename from unified/src/algebra/jsruntime.rs
rename to core/unified/src/algebra/jsruntime.rs
diff --git a/unified/src/algebra/mod.rs b/core/unified/src/algebra/mod.rs
similarity index 100%
rename from unified/src/algebra/mod.rs
rename to core/unified/src/algebra/mod.rs
diff --git a/unified/src/client.rs b/core/unified/src/client.rs
similarity index 100%
rename from unified/src/client.rs
rename to core/unified/src/client.rs
diff --git a/unified/src/domain/mod.rs b/core/unified/src/domain/mod.rs
similarity index 100%
rename from unified/src/domain/mod.rs
rename to core/unified/src/domain/mod.rs
diff --git a/unified/src/helper/mod.rs b/core/unified/src/helper/mod.rs
similarity index 100%
rename from unified/src/helper/mod.rs
rename to core/unified/src/helper/mod.rs
diff --git a/unified/src/lib.rs b/core/unified/src/lib.rs
similarity index 100%
rename from unified/src/lib.rs
rename to core/unified/src/lib.rs
diff --git a/unified/src/unified.rs b/core/unified/src/unified.rs
similarity index 100%
rename from unified/src/unified.rs
rename to core/unified/src/unified.rs
diff --git a/watchdog/Cargo.toml b/core/watchdog/Cargo.toml
similarity index 100%
rename from watchdog/Cargo.toml
rename to core/watchdog/Cargo.toml
diff --git a/watchdog/Dockerfile b/core/watchdog/Dockerfile
similarity index 100%
rename from watchdog/Dockerfile
rename to core/watchdog/Dockerfile
diff --git a/watchdog/README.md b/core/watchdog/README.md
similarity index 100%
rename from watchdog/README.md
rename to core/watchdog/README.md
diff --git a/watchdog/src/client.rs b/core/watchdog/src/client.rs
similarity index 100%
rename from watchdog/src/client.rs
rename to core/watchdog/src/client.rs
diff --git a/watchdog/src/config.rs b/core/watchdog/src/config.rs
similarity index 100%
rename from watchdog/src/config.rs
rename to core/watchdog/src/config.rs
diff --git a/watchdog/src/main.rs b/core/watchdog/src/main.rs
similarity index 100%
rename from watchdog/src/main.rs
rename to core/watchdog/src/main.rs
diff --git a/workflows/README.md b/workflows/README.md
new file mode 100644
index 00000000..8276d920
--- /dev/null
+++ b/workflows/README.md
@@ -0,0 +1 @@
+# Coming Soon
\ No newline at end of file