# API Reference Source: https://docs.crewship.dev/api-reference/introduction Crewship REST API for programmatic access ## Overview The Crewship API allows you to programmatically: * Trigger and monitor runs * Stream real-time events * Manage threads for stateful conversations * Store and query structured data tables ## Base URL ``` https://api.crewship.dev ``` ## Authentication All API requests require authentication using an API key: ```bash theme={null} curl https://api.crewship.dev/v1/runs \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Getting an API Key 1. Open the [Crewship Console](https://console.crewship.dev) 2. Go to **Settings** → **API Keys** 3. Click **Create API Key** 4. Copy and store the key securely API keys are shown only once. Store them securely and never commit them to version control. ## Request Format ### Headers | Header | Required | Description | | --------------- | ------------ | --------------------- | | `Authorization` | Yes | `Bearer YOUR_API_KEY` | | `Content-Type` | For POST/PUT | `application/json` | ### Request Body POST requests accept JSON: ```bash theme={null} curl -X POST https://api.crewship.dev/v1/runs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "deployment_id": "dep_abc123xyz", "input": {"topic": "AI agents"} }' ``` ## Response Format ### Success Responses Responses return JSON objects directly: ```json theme={null} { "run_id": "run_abc123", "version_id": "ver_xyz789", "version_number": 3, "status": "running" } ``` ### List Responses List endpoints return arrays under a named key: ```json theme={null} { "runs": [ { "id": "run_abc123", "status": "succeeded", ... }, { "id": "run_xyz789", "status": "running", ... } ] } ``` ### Error Responses ```json theme={null} { "error": { "message": "deployment_id is required" } } ``` ## HTTP Status Codes | Code | Description | | ----- | -------------------------------- | | `200` | Success | | `201` | Created | | `202` | Accepted (async operation) | | `400` | Bad request (invalid parameters) | | `401` | Unauthorized (invalid API key) | | `404` | Not found | | `409` | Conflict (e.g., thread is busy) | | `503` | Service unavailable | ## SDKs Coming soon Coming soon Coming soon ## API Endpoints Trigger and monitor runs Stateful conversation threads Structured table storage and row operations # Cancel Run Source: https://docs.crewship.dev/api-reference/runs/cancel POST /v1/runs/{id}/cancel Cancel a running or pending run ## Path Parameters Run ID (e.g., `run_xyz789abc`) ## Response Whether the cancellation was successful The updated run status (`canceled`) ```bash cURL theme={null} curl -X POST https://api.crewship.dev/v1/runs/run_xyz789abc/cancel \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json Success theme={null} { "success": true, "status": "canceled" } ``` ```json Error - Invalid status theme={null} { "error": { "code": "bad_request", "message": "Cannot cancel run with status: succeeded" } } ``` ## Notes * Only runs with status `pending` or `running` can be canceled * Canceling a run stops execution and destroys the underlying machine * The run status will be set to `canceled` with a `completed_at` timestamp # Create Run Source: https://docs.crewship.dev/api-reference/runs/create POST /v1/runs Trigger a new run of your deployed crew ## Request Deployment ID Input data passed to your crew's kickoff function Environment to run in: `production` or `staging` ## Response Returns HTTP 202 (Accepted). Run ID (e.g., `run_abc123xyz`) Version ID used for this run Version number used for this run Run status: `running` ```bash cURL theme={null} curl -X POST https://api.crewship.dev/v1/runs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "deployment_id": "dep_abc123xyz", "input": { "topic": "AI agents", "style": "technical" } }' ``` ```json Success theme={null} { "run_id": "run_xyz789abc", "version_id": "ver_abc123xyz", "version_number": 3, "status": "running" } ``` ```json Error theme={null} { "error": { "message": "No running version found for production environment" } } ``` ## Notes * Runs are created and executed asynchronously * Use the [Stream Events](/api-reference/runs/events) endpoint to get real-time updates * Poll the [Get Run](/api-reference/runs/get) endpoint for completion status # Stream Events Source: https://docs.crewship.dev/api-reference/runs/events GET /v1/runs/{id}/events Stream real-time events from a run using Server-Sent Events (SSE) ## Path Parameters Run ID (e.g., `run_xyz789abc`) ## Event Format Events are sent as SSE `data` messages with JSON payloads: ``` data: {"type":"run.started","data":{"entrypoint":"default"}} data: {"type":"task.started","data":{"task":"Research AI trends","agent":"Researcher"}} data: {"type":"log","data":{"message":"Found 15 relevant results"}} ``` ## Event Types When the runner machine is reachable, you receive detailed events from the crew execution: | Type | Description | | ---------------- | ---------------------------- | | `run.started` | Run execution began | | `run.completed` | Run finished successfully | | `run.failed` | Run encountered an error | | `task.started` | A task began execution | | `task.completed` | A task finished | | `agent.action` | An agent performed an action | | `tool_use` | A tool was invoked | | `log` | Log message from the crew | | `artifact` | An artifact was produced | If the runner machine is not reachable, the API falls back to polling the database and sends simpler status events: | Type | Description | | ----------- | ---------------------------------------------------------------- | | `heartbeat` | Periodic status update while the run is in progress | | `complete` | Run reached a terminal state (`succeeded`, `failed`, `canceled`) | | `error` | An error occurred (e.g., run not found) | | `timeout` | The SSE connection timed out | ```bash cURL theme={null} curl -N \ -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.crewship.dev/v1/runs/run_xyz789abc/events" ``` ```javascript JavaScript theme={null} const response = await fetch('https://api.crewship.dev/v1/runs/run_xyz789abc/events', { headers: { Authorization: 'Bearer YOUR_API_KEY', }, }) const reader = response.body.getReader() const decoder = new TextDecoder() let buffer = '' while (true) { const { done, value } = await reader.read() if (done) break buffer += decoder.decode(value, { stream: true }) const lines = buffer.split('\n') buffer = lines.pop() || '' for (const line of lines) { if (line.startsWith('data: ')) { const event = JSON.parse(line.slice(6)) console.log(event.type, event) if (['complete', 'run.completed', 'run.failed'].includes(event.type)) { console.log('Run finished') return } } } } ``` ```text SSE Stream (runner connected) theme={null} data: {"type":"run.started","data":{"entrypoint":"default"}} data: {"type":"task.started","data":{"task":"Research AI trends","agent":"Researcher"}} data: {"type":"log","data":{"message":"Found 15 relevant results"}} data: {"type":"task.completed","data":{"task":"Research AI trends","agent":"Researcher"}} data: {"type":"artifact","data":{"name":"report.md"}} data: {"type":"run.completed","data":{"status":"succeeded"}} ``` ```text SSE Stream (fallback polling) theme={null} data: {"type":"heartbeat","status":"running"} data: {"type":"heartbeat","status":"running"} data: {"type":"complete","status":"succeeded","output":{"result":"Generated report..."},"error":null} ``` ## Notes * If the run is already in a terminal state (`succeeded`, `failed`, `canceled`), a single `complete` event is returned immediately * If the runner machine is reachable, events are proxied directly from the machine in real time * If the machine is not reachable, the API falls back to polling the database every 2 seconds and sending `heartbeat` events * The connection times out after 30 minutes # Get Run Source: https://docs.crewship.dev/api-reference/runs/get GET /v1/runs/{id} Retrieve a specific run by ID ## Path Parameters Run ID (e.g., `run_xyz789abc`) ## Response Run ID Version ID Deployment ID Run status: `pending`, `running`, `succeeded`, `failed`, `canceled` Input provided when creating the run Final output (only present when succeeded) Error message (only present when failed) When the run was created (ISO 8601) When execution started (ISO 8601), or `null` When the run finished (ISO 8601), or `null` ```bash cURL theme={null} curl https://api.crewship.dev/v1/runs/run_xyz789abc \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json Running theme={null} { "id": "run_xyz789abc", "version_id": "ver_abc123xyz", "deployment_id": "dep_abc123xyz", "status": "running", "input": { "topic": "AI agents" }, "output": null, "error_message": null, "created_at": "2024-01-15T10:35:00Z", "started_at": "2024-01-15T10:35:02Z", "completed_at": null } ``` ```json Succeeded theme={null} { "id": "run_xyz789abc", "version_id": "ver_abc123xyz", "deployment_id": "dep_abc123xyz", "status": "succeeded", "input": { "topic": "AI agents" }, "output": { "result": "Generated report about AI agents..." }, "error_message": null, "created_at": "2024-01-15T10:35:00Z", "started_at": "2024-01-15T10:35:02Z", "completed_at": "2024-01-15T10:35:47Z" } ``` ```json Failed theme={null} { "id": "run_xyz789abc", "version_id": "ver_abc123xyz", "deployment_id": "dep_abc123xyz", "status": "failed", "input": { "topic": "AI agents" }, "output": null, "error_message": "OpenAI API rate limit exceeded", "created_at": "2024-01-15T10:35:00Z", "started_at": "2024-01-15T10:35:02Z", "completed_at": "2024-01-15T10:35:05Z" } ``` # List Runs Source: https://docs.crewship.dev/api-reference/runs/list GET /v1/runs List runs for a deployment ## Query Parameters Deployment ID to list runs for ## Response Array of run objects Each run object contains: Run ID Version ID Version number Run status: `pending`, `running`, `succeeded`, `failed`, `canceled` When the run was created (ISO 8601) When execution started (ISO 8601), or `null` When the run finished (ISO 8601), or `null` ```bash cURL theme={null} curl "https://api.crewship.dev/v1/runs?deployment_id=dep_abc123xyz" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json Success theme={null} { "runs": [ { "id": "run_xyz789abc", "version_id": "ver_abc123xyz", "version_number": 3, "status": "succeeded", "created_at": "2024-01-15T10:35:00Z", "started_at": "2024-01-15T10:35:02Z", "completed_at": "2024-01-15T10:35:47Z" }, { "id": "run_def456ghi", "version_id": "ver_abc123xyz", "version_number": 3, "status": "succeeded", "created_at": "2024-01-15T09:20:00Z", "started_at": "2024-01-15T09:20:01Z", "completed_at": "2024-01-15T09:21:12Z" } ] } ``` # Bulk Update Rows Source: https://docs.crewship.dev/api-reference/tables/bulk-update-rows PATCH /v1/tables/{id}/rows Update all rows matching a filter ## Path Parameters Table ID ## Request Filter expression selecting rows to update Column values to apply to all matched rows ## Response Number of rows updated ```bash cURL theme={null} curl -X PATCH https://api.crewship.dev/v1/tables/tbl_abc123xyz789/rows \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "and": [ {"column": "status", "operator": "eq", "value": "new"} ] }, "update": { "status": "qualified" } }' ``` ```json Success theme={null} { "updated": 18 } ``` # Create Table Source: https://docs.crewship.dev/api-reference/tables/create POST /v1/tables Create a new data table ## Request Table name (unique within your organization) Optional table description Column definitions for the table Column name Column type: `text`, `number`, `boolean`, `datetime`, `select`, `url`, `email`, `json` Whether the column is required on inserts Required for `select` columns ## Response Returns HTTP 201 (Created). Table ID (e.g., `tbl_abc123xyz789`) Table name Table description or `null` Persisted column definitions Initial row count (`0`) ISO 8601 timestamp ISO 8601 timestamp ```bash cURL theme={null} curl -X POST https://api.crewship.dev/v1/tables \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "leads", "description": "Sales prospects", "columns": [ {"name": "company", "type": "text", "required": true}, {"name": "score", "type": "number"}, {"name": "status", "type": "select", "options": ["new", "qualified"]} ] }' ``` ```json Success theme={null} { "id": "tbl_abc123xyz789", "name": "leads", "description": "Sales prospects", "columns": [ { "name": "company", "type": "text", "required": true }, { "name": "score", "type": "number", "required": false }, { "name": "status", "type": "select", "required": false, "options": ["new", "qualified"] } ], "row_count": 0, "created_at": "2024-01-15T10:35:00Z", "updated_at": "2024-01-15T10:35:00Z" } ``` ```json Error theme={null} { "error": { "message": "Table \"leads\" already exists" } } ``` # Delete Table Source: https://docs.crewship.dev/api-reference/tables/delete DELETE /v1/tables/{id} Delete a table and all of its rows ## Path Parameters Table ID ## Response `true` when the table was deleted ```bash cURL theme={null} curl -X DELETE https://api.crewship.dev/v1/tables/tbl_abc123xyz789 \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json Success theme={null} { "success": true } ``` ```json Error theme={null} { "error": { "message": "Table not found" } } ``` ## Notes * Deleting a table also deletes all rows in that table. * This action cannot be undone. # Delete Row Source: https://docs.crewship.dev/api-reference/tables/delete-row DELETE /v1/tables/{id}/rows/{rowId} Delete a single row ## Path Parameters Table ID Row ID ## Response `true` when the row was deleted ```bash cURL theme={null} curl -X DELETE https://api.crewship.dev/v1/tables/tbl_abc123xyz789/rows/row_abc123xyz789 \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json Success theme={null} { "success": true } ``` ```json Error theme={null} { "error": { "message": "Row not found" } } ``` # Get Table Source: https://docs.crewship.dev/api-reference/tables/get GET /v1/tables/{id} Get a table definition and metadata ## Path Parameters Table ID ## Response Table ID Table name Table description or `null` Column definitions Number of rows in the table ISO 8601 timestamp ISO 8601 timestamp ```bash cURL theme={null} curl https://api.crewship.dev/v1/tables/tbl_abc123xyz789 \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json Success theme={null} { "id": "tbl_abc123xyz789", "name": "leads", "description": "Sales prospects", "columns": [ { "name": "company", "type": "text", "required": true }, { "name": "score", "type": "number", "required": false } ], "row_count": 42, "created_at": "2024-01-15T10:35:00Z", "updated_at": "2024-01-20T08:12:00Z" } ``` ```json Error theme={null} { "error": { "message": "Table not found" } } ``` # Get Row Source: https://docs.crewship.dev/api-reference/tables/get-row GET /v1/tables/{id}/rows/{rowId} Get a single row by ID ## Path Parameters Table ID Row ID ## Response Returns a row object with user-defined fields plus metadata. Row ID Metadata (`created_at`, `created_by`, `updated_at`, `updated_by`) ```bash cURL theme={null} curl https://api.crewship.dev/v1/tables/tbl_abc123xyz789/rows/row_abc123xyz789 \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json Success theme={null} { "id": "row_abc123xyz789", "company": "Acme", "score": 92, "status": "qualified", "_meta": { "created_at": "2024-01-15T10:35:00Z", "created_by": "api:Production Key", "updated_at": "2024-01-20T08:12:00Z", "updated_by": "api:Production Key" } } ``` ```json Error theme={null} { "error": { "message": "Row not found" } } ``` # Insert Rows Source: https://docs.crewship.dev/api-reference/tables/insert-rows POST /v1/tables/{id}/rows Insert one or more rows into a table ## Path Parameters Table ID ## Request Provide either: * A single row object, or * An array of row objects (max 100 rows) Keys should match table column names. ## Response For single-row inserts, the API returns one row object. For multi-row inserts, the API returns: Inserted row objects Each row includes: Row ID (e.g., `row_abc123xyz789`) Row metadata (`created_at`, `created_by`, `updated_at`, `updated_by`) ```bash cURL theme={null} curl -X POST https://api.crewship.dev/v1/tables/tbl_abc123xyz789/rows \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '[ {"company": "Acme", "score": 92, "status": "qualified"}, {"company": "Beta", "score": 70, "status": "new"} ]' ``` ```json Success theme={null} { "rows": [ { "id": "row_abc123xyz789", "company": "Acme", "score": 92, "status": "qualified", "_meta": { "created_at": "2024-01-15T10:35:00Z", "created_by": "api:Production Key", "updated_at": "2024-01-15T10:35:00Z", "updated_by": "api:Production Key" } }, { "id": "row_def456uvw000", "company": "Beta", "score": 70, "status": "new", "_meta": { "created_at": "2024-01-15T10:35:01Z", "created_by": "api:Production Key", "updated_at": "2024-01-15T10:35:01Z", "updated_by": "api:Production Key" } } ] } ``` ```json Error theme={null} { "error": { "message": "Maximum 100 rows per insert" } } ``` # List Tables Source: https://docs.crewship.dev/api-reference/tables/list GET /v1/tables List data tables for the authenticated organization ## Query Parameters Number of tables to return (max 1000) Number of tables to skip ## Response Array of tables in the organization Table ID (e.g., `tbl_abc123xyz789`) Table name Optional table description Column definitions for the table Number of rows in the table ISO 8601 timestamp ISO 8601 timestamp ```bash cURL theme={null} curl "https://api.crewship.dev/v1/tables?limit=20&offset=0" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json Success theme={null} { "tables": [ { "id": "tbl_abc123xyz789", "name": "leads", "description": "Sales pipeline leads", "columns": [ { "name": "company", "type": "text", "required": true }, { "name": "score", "type": "number", "required": false } ], "row_count": 42, "created_at": "2024-01-15T10:35:00Z", "updated_at": "2024-01-20T08:12:00Z" } ] } ``` # Query Rows Source: https://docs.crewship.dev/api-reference/tables/query-rows POST /v1/tables/{id}/query Query table rows with filtering, sorting, and pagination ## Path Parameters Table ID ## Request Filter expression. Use `and` / `or` groups with conditions like `{ "column": "score", "operator": "gte", "value": 10 }` Column name to sort by Sort direction: `asc` or `desc` Rows to return (max 1000) Rows to skip ## Response Matching rows Total rows matching the filter Effective limit used Effective offset used ```bash cURL theme={null} curl -X POST https://api.crewship.dev/v1/tables/tbl_abc123xyz789/query \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filter": { "and": [ { "column": "status", "operator": "eq", "value": "qualified" }, { "column": "score", "operator": "gte", "value": 50 } ] }, "sort_by": "score", "sort_direction": "desc", "limit": 25, "offset": 0 }' ``` ```json Success theme={null} { "rows": [ { "id": "row_abc123xyz789", "company": "Acme", "score": 92, "status": "qualified", "_meta": { "created_at": "2024-01-15T10:35:00Z", "created_by": "api:Production Key", "updated_at": "2024-01-20T08:12:00Z", "updated_by": "api:Production Key" } } ], "total": 1, "limit": 25, "offset": 0 } ``` # Update Table Source: https://docs.crewship.dev/api-reference/tables/update PATCH /v1/tables/{id} Update table name, description, or columns ## Path Parameters Table ID ## Request New table name New description (`null` clears the description) Full replacement of column definitions ## Response Table ID Updated table name Updated description Updated column definitions Current row count ISO 8601 timestamp ISO 8601 timestamp ```bash cURL theme={null} curl -X PATCH https://api.crewship.dev/v1/tables/tbl_abc123xyz789 \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "qualified_leads", "description": "Only qualified prospects" }' ``` ```json Success theme={null} { "id": "tbl_abc123xyz789", "name": "qualified_leads", "description": "Only qualified prospects", "columns": [ { "name": "company", "type": "text", "required": true }, { "name": "score", "type": "number", "required": false } ], "row_count": 42, "created_at": "2024-01-15T10:35:00Z", "updated_at": "2024-01-20T08:12:00Z" } ``` # Update Row Source: https://docs.crewship.dev/api-reference/tables/update-row PATCH /v1/tables/{id}/rows/{rowId} Update fields on a single row ## Path Parameters Table ID Row ID ## Request Body is a partial row object. Only provided fields are updated. Value to update for a table column ## Response Returns the updated row object. ```bash cURL theme={null} curl -X PATCH https://api.crewship.dev/v1/tables/tbl_abc123xyz789/rows/row_abc123xyz789 \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "score": 95, "status": "qualified" }' ``` ```json Success theme={null} { "id": "row_abc123xyz789", "company": "Acme", "score": 95, "status": "qualified", "_meta": { "created_at": "2024-01-15T10:35:00Z", "created_by": "api:Production Key", "updated_at": "2024-01-20T08:12:00Z", "updated_by": "api:Production Key" } } ``` # Create Thread Source: https://docs.crewship.dev/api-reference/threads/create POST /v1/threads Create a new thread for a deployment ## Request Deployment ID to scope this thread to User-defined metadata (e.g., user ID, session info) Initial thread state values ## Response Thread ID (e.g., `thr_abc123xyz`) Deployment ID Thread status: `idle` User-defined metadata ISO 8601 timestamp ```bash cURL theme={null} curl -X POST https://api.crewship.dev/v1/threads \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "deployment_id": "dep_abc123", "metadata": {"user_id": "user_1"} }' ``` ```json Success theme={null} { "thread_id": "thr_xyz789abc", "deployment_id": "dep_abc123", "status": "idle", "metadata": {"user_id": "user_1"}, "values": null, "created_at": "2024-01-15T10:35:00Z", "updated_at": "2024-01-15T10:35:00Z" } ``` # Get Thread Source: https://docs.crewship.dev/api-reference/threads/get GET /v1/threads/{id} Get thread details ## Path Parameters Thread ID ## Response Thread ID Deployment ID Thread status: `idle`, `busy`, `interrupted`, `error` Current thread state User-defined metadata ```bash cURL theme={null} curl https://api.crewship.dev/v1/threads/thr_xyz789abc \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json Success theme={null} { "thread_id": "thr_xyz789abc", "deployment_id": "dep_abc123", "status": "idle", "metadata": {"user_id": "user_1"}, "values": {"messages": [{"role": "user", "content": "Hello"}]}, "created_at": "2024-01-15T10:35:00Z", "updated_at": "2024-01-15T10:40:00Z" } ``` # List Threads Source: https://docs.crewship.dev/api-reference/threads/list GET /v1/threads List threads for a deployment ## Query Parameters Deployment ID to filter threads Filter by status: `idle`, `busy`, `interrupted`, `error` Number of threads to return Offset for pagination ## Response Array of thread objects ```bash cURL theme={null} curl "https://api.crewship.dev/v1/threads?deployment_id=dep_abc123" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json Success theme={null} { "threads": [ { "thread_id": "thr_xyz789abc", "deployment_id": "dep_abc123", "status": "idle", "metadata": {"user_id": "user_1"}, "values": null, "created_at": "2024-01-15T10:35:00Z", "updated_at": "2024-01-15T10:35:00Z" } ] } ``` # Create Thread Run Source: https://docs.crewship.dev/api-reference/threads/runs POST /v1/threads/{id}/runs Create a new run in thread context ## Path Parameters Thread ID ## Request Input data passed to your crew Environment: `production` or `staging` ## Response Returns HTTP 202 (Accepted). Run ID Thread ID Version ID used for this run Version number used for this run Run status: `running` ## Notes * The thread must be in `idle` status. If `busy`, returns 409. * Thread is automatically set to `busy` during execution. * Thread state is updated and a checkpoint is created on completion. ```bash cURL theme={null} curl -X POST https://api.crewship.dev/v1/threads/thr_xyz789abc/runs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": {"message": "Tell me about AI agents"} }' ``` ```json Success theme={null} { "run_id": "run_abc123xyz", "thread_id": "thr_xyz789abc", "version_id": "ver_xyz789", "version_number": 3, "status": "running" } ``` # crewship deploy Source: https://docs.crewship.dev/cli/deploy Deploy your crew to Crewship ## Usage ```bash theme={null} crewship deploy [path] [options] ``` ## Description Packages your crew and deploys it to Crewship, or builds a local Docker image for testing. **Remote deploy** (default): 1. **Packages** your project into a tarball 2. **Initializes** a deployment (or uses existing one based on project name) 3. **Creates** a new version 4. **Uploads** the build context to Crewship **Local deploy** (`--local`): 1. **Builds** a Docker image locally using the base Crewship image 2. Optionally **runs** the container ## Options | Option | Description | | --------------- | ------------------------------------------------- | | `[path]` | Project directory (defaults to current directory) | | `--name`, `-n` | Deployment name (for multi-deployment configs) | | `--local`, `-l` | Build Docker image locally instead of deploying | | `--run`, `-r` | Run the container after building (with `--local`) | | `--port`, `-p` | Port to expose when running (default: 8000) | ## Examples ### Deploy to Crewship ```bash theme={null} crewship deploy ``` ### Deploy a specific directory ```bash theme={null} crewship deploy ./my-crew ``` ### Build and test locally ```bash theme={null} crewship deploy --local ``` ### Build and run locally ```bash theme={null} crewship deploy --local --run ``` ### Run on a custom port ```bash theme={null} crewship deploy --local --run --port 9000 ``` ### Deploy a named deployment (multi-deployment) ```bash theme={null} crewship deploy --name research-agent ``` If your `crewship.toml` has multiple `[deployments.]` sections and you omit `--name`, the CLI prompts you to select one interactively. ## Output ### Remote Deploy A successful remote deployment shows: ``` 🚀 Deploying crew "my-crew" to Crewship 📡 Fetching organizations... Using organization: My Org (my-org) 📝 Initializing deployment... Created new deployment: dep_abc123xyz Saved deployment ID to crewship.toml 📝 Creating new version... Version: 1 (ver_xyz789) 📦 Packaging project... Package size: 0.12 MB ⬆️ Uploading context... Status: pending ✅ Deployed version 1 for "my-crew"! Deployment ID: dep_abc123xyz Version: 1 Status: pending View in console: https://console.crewship.dev/deployments/dep_abc123xyz ``` ### Local Deploy A successful local build shows: ``` 🚀 Deploying crew locally from /path/to/my-crew Framework: crewai Entrypoint: src.my_crew.main:kickoff Profile: slim Image: crewship-my-crew:latest 📦 Reading .env file... Found 3 environment variables 🔨 Building image... ✓ Image built: crewship-my-crew:latest To run the crew locally: docker run -p 8000:8000 crewship-my-crew:latest Or use: crewship deploy --local --run ``` ## Requirements Your project must have: * `crewship.toml` in the project root with a `[deployment]` or `[deployments.]` section * A valid `entrypoint` pointing to your crew's kickoff function * `pyproject.toml` for dependencies (installed via `uv pip install -e .`) ### Single deployment ```toml crewship.toml theme={null} [deployment] framework = "crewai" entrypoint = "src.my_crew.main:kickoff" ``` ### Multiple deployments ```toml crewship.toml theme={null} [build] exclude = ["tests"] [deployments.research-agent] framework = "crewai" entrypoint = "research_crew.crew:ResearchCrew" [deployments.writer-agent] framework = "crewai" entrypoint = "writer_crew.crew:WriterCrew" ``` See the [crewship.toml reference](/configuration/crewship-toml) for details. ## Build Process For local builds, Crewship generates a Dockerfile based on your configuration: ```dockerfile theme={null} FROM crewship/crewai:py311-slim # Copy project files COPY . /app/project/ # Install dependencies WORKDIR /app/project RUN uv pip install -e . WORKDIR /app # Configure entrypoint ENV CREWSHIP_ENTRYPOINT=src.my_crew.main:kickoff ``` You don't need to write a Dockerfile. Crewship generates one based on your `crewship.toml`. ## Excluding Files By default, the following files and directories are excluded from the build: * `.git`, `.gitignore` * `.env`, `.env.*` * `.venv`, `venv` * `__pycache__`, `*.pyc`, `*.pyo` * `.pytest_cache`, `.mypy_cache`, `.ruff_cache` * `node_modules` * `.DS_Store`, `Thumbs.db` * `*.egg-info`, `dist`, `build` * `.idea`, `.vscode` * `*.log` * `Dockerfile`, `.dockerignore` To exclude additional files, add them to your `crewship.toml`: ```toml crewship.toml theme={null} [deployment] framework = "crewai" entrypoint = "src.my_crew.main:kickoff" [build] exclude = [ "tests/", "data/*.csv", "*.md", ] ``` ## Troubleshooting ### "crewship.toml not found" Make sure you're in the project root directory and have a `crewship.toml` file. Run `crewship init` to create one. ### "Not logged in" Run `crewship login` to authenticate before deploying to Crewship. ### "Missing deployment.framework" or "Missing deployment.entrypoint" Your `crewship.toml` must have a `[deployment]` or `[deployments.]` section with both `framework` and `entrypoint`: ```toml theme={null} [deployment] framework = "crewai" entrypoint = "src.my_crew.main:kickoff" ``` ### "No organizations found" Create an organization in the [Console](https://console.crewship.dev) before deploying. ### "Session expired" Your login session has expired. Run `crewship login` again. ### Local build: "Base image not found" For local builds, the CLI will attempt to build the base image automatically. If this fails, ensure Docker is running and you have access to the `packages/runner-crewai` directory. ## Related Configure your deployment Set secrets before deploying # crewship deployment Source: https://docs.crewship.dev/cli/deployment List and delete deployments ## Overview Manage your deployments from the command line. List all deployments in your organization or delete deployments you no longer need. ## Commands ### List Deployments ```bash theme={null} crewship deployment list ``` Output: ``` Deployments (2) my-research-crew ID: dep_abc123def456 Framework: crewai Production: v3 (running) Created: 1/15/2025, 10:30:00 AM my-writer-crew ID: dep_xyz789ghi012 Framework: crewai Production: v1 (running) Staging: v2 (building) Created: 1/20/2025, 2:15:00 PM ``` ### Delete a Deployment ```bash theme={null} crewship deployment delete ``` This soft-deletes the deployment and all its versions. Existing in-flight runs will complete normally, but no new runs can be created. Deletion cannot be undone. All versions associated with the deployment will also be deleted. ### Options | Option | Description | | -------------- | ---------------------------------------------- | | `--name`, `-n` | Deployment name (for multi-deployment configs) | | `--force` | Skip confirmation prompt | ### Resolving the Deployment If no deployment ID is provided, it is resolved from `crewship.toml` in the current directory: ```bash theme={null} # Uses deployment ID from crewship.toml crewship deployment delete # Specify a deployment in a multi-deployment config crewship deployment delete --name research-agent ``` ## Examples ### List all deployments ```bash theme={null} crewship deployment list ``` ### Delete by ID ```bash theme={null} crewship deployment delete dep_abc123def456 ``` ### Delete with auto-resolve from config ```bash theme={null} # In a directory with crewship.toml crewship deployment delete # Skip confirmation crewship deployment delete --force ``` ### Delete a named deployment ```bash theme={null} crewship deployment delete --name research-agent --force ``` ## Related Manage versions Deploy your crew # crewship env Source: https://docs.crewship.dev/cli/env Manage environment variables for your crew ## Overview Environment variables let you configure your crew without changing code. Use them for: * API keys (OpenAI, Anthropic, etc.) * External service credentials * Configuration that varies between environments ## Commands ### Set Variables ```bash theme={null} crewship env set KEY=value ``` Set multiple variables at once: ```bash theme={null} crewship env set OPENAI_API_KEY=sk-... ANTHROPIC_API_KEY=sk-ant-... ``` ### Options | Option | Description | | ------------------ | ---------------------------------------------- | | `--name`, `-n` | Deployment name (for multi-deployment configs) | | `--project ` | Target project (defaults to current directory) | ### List Variables ```bash theme={null} crewship env list ``` Output: ``` Environment variables for my-crew: OPENAI_API_KEY sk-...xxxx (set 2 days ago) ANTHROPIC_API_KEY sk-ant-...xxxx (set 2 days ago) DEBUG_MODE false (set 5 days ago) 3 variables ``` Values are masked for security. Only the first and last few characters are shown. ### Get a Variable ```bash theme={null} crewship env get OPENAI_API_KEY ``` Shows the masked value: ``` OPENAI_API_KEY=sk-...xxxx ``` ### Remove Variables ```bash theme={null} crewship env rm VARIABLE_NAME ``` Remove multiple: ```bash theme={null} crewship env rm VAR1 VAR2 VAR3 ``` ## Examples ### Setting API keys ```bash theme={null} # OpenAI crewship env set OPENAI_API_KEY=sk-proj-... # Anthropic crewship env set ANTHROPIC_API_KEY=sk-ant-... # Serper (for web search) crewship env set SERPER_API_KEY=... ``` ### Configuration variables ```bash theme={null} crewship env set LOG_LEVEL=debug crewship env set MAX_RETRIES=3 ``` ### Multi-deployment projects Target a specific named deployment: ```bash theme={null} crewship env set --name research-agent OPENAI_API_KEY=sk-... crewship env list --name writer-agent ``` ### Using in your crew Variables are automatically available as environment variables: ```python theme={null} import os openai_key = os.environ["OPENAI_API_KEY"] log_level = os.environ.get("LOG_LEVEL", "info") ``` Or with CrewAI's built-in support: ```python theme={null} from crewai import Agent, LLM # CrewAI automatically uses OPENAI_API_KEY agent = Agent( role="Researcher", llm=LLM(model="gpt-4o") ) ``` ## Loading from .env Load variables from a `.env` file: ```bash theme={null} crewship env set --file .env ``` Never commit `.env` files to version control. Add `.env` to your `.gitignore`. ## Variable Scope Environment variables are scoped to a **project**, not a deployment. This means: * All deployments in a project share the same variables * Updating a variable affects all future runs * No redeploy is needed after changing variables ## Encryption All environment variables are: * Encrypted at rest using AES-256 * Transmitted over TLS * Never logged or exposed in build output ## Reserved Variables These variables are set by Crewship and cannot be overridden: | Variable | Description | | ------------------------ | --------------------- | | `CREWSHIP_RUN_ID` | Current run ID | | `CREWSHIP_DEPLOYMENT_ID` | Current deployment ID | | `CREWSHIP_PROJECT` | Project name | ## Best Practices Name variables clearly: `OPENAI_API_KEY` not `KEY1` Use different projects for staging and production Update API keys periodically for security Fail fast if a required variable is missing instead of using default values for secrets ## Related Project configuration Deploy your crew # crewship init Source: https://docs.crewship.dev/cli/init Initialize a crewship.toml configuration file ## Usage ```bash theme={null} crewship init [directory] ``` Initialize a new `crewship.toml` configuration file in your project. This command auto-detects your project settings and creates a ready-to-use configuration. ## Arguments | Argument | Description | | ----------- | ------------------------------------------------- | | `directory` | Project directory (defaults to current directory) | ## What It Does The `init` command: 1. **Detects your framework** - Looks for `[tool.crewai]` in `pyproject.toml` to identify CrewAI projects 2. **Finds your entrypoint** - Searches for crew classes decorated with `@CrewBase` or named `*Crew` 3. **Extracts Python version** - Reads `requires-python` from `pyproject.toml` 4. **Creates configuration** - Generates a `crewship.toml` with sensible defaults ## Examples ### Initialize current directory ```bash theme={null} cd my-crew crewship init ``` Output: ``` 🔍 Initializing Crewship project in /path/to/my-crew Found pyproject.toml, reading project info... Detected CrewAI project Detected entrypoint: my_crew.crew:MyCrew ✅ Created crewship.toml Framework: crewai Entrypoint: my_crew.crew:MyCrew Profile: slim Python: 3.11 Edit crewship.toml to customize your deployment settings. Then run "crewship deploy" to deploy your crew. ``` ### Initialize a specific directory ```bash theme={null} crewship init ./projects/my-crew ``` ## Generated Configuration The command creates a `crewship.toml` like this: ```toml theme={null} [deployment] framework = "crewai" entrypoint = "my_crew.crew:MyCrew" profile = "slim" python = "3.11" [build] exclude = ["tests"] ``` ## Entrypoint Detection The command searches for your crew entrypoint in these locations: 1. `/crew.py` - Standard CrewAI structure 2. `src//crew.py` - Source layout 3. Any top-level package with a `crew.py` file It looks for: * Classes decorated with `@CrewBase` * Classes with names ending in `Crew` If auto-detection fails, a default entrypoint is generated based on your project name. ## After Initialization Once you have a `crewship.toml`, you can: 1. **Edit the configuration** - Customize entrypoint, profile, or build settings 2. **Set environment variables** - Add API keys with `crewship env set` 3. **Deploy** - Run `crewship deploy` to deploy your crew ## Related Full configuration options Deploy your crew # crewship invoke Source: https://docs.crewship.dev/cli/invoke Run your deployed crew ## Usage ```bash theme={null} crewship invoke [options] ``` ## Description Triggers a new run of your deployed crew. You can pass input data and stream events in real-time. ## Options | Option | Description | | --------------------- | ------------------------------------------------- | | `--name`, `-n` | Deployment name (for multi-deployment configs) | | `--input ` | JSON input to pass to your crew | | `--input-file ` | Read input from a JSON file | | `--stream` | Stream events in real-time | | `--project ` | Project to invoke (defaults to current directory) | | `--deployment ` | Specific deployment to run (defaults to latest) | | `--wait` | Wait for completion and show result | | `--timeout ` | Maximum time to wait (default: 300) | ## Examples ### Basic invocation ```bash theme={null} crewship invoke --input '{"topic": "AI agents"}' ``` Output: ``` ▶ Run started: run_abc123xyz Status: running Use `crewship runs get run_abc123xyz` to check status. ``` ### Stream events ```bash theme={null} crewship invoke --input '{"topic": "quantum computing"}' --stream ``` Real-time output: ``` ▶ Run started: run_abc123xyz ├─ [10:30:01] Researcher agent starting task... ├─ [10:30:15] Tool: web_search("quantum computing breakthroughs 2024") ├─ [10:30:18] Researcher agent completed task ├─ [10:30:19] Writer agent starting task... ├─ [10:30:45] Writer agent completed task ├─ [10:30:46] Artifact: research_report.md (4.2 KB) ✅ Run completed in 45.2s ``` ### Input from file ```bash theme={null} # Create input file echo '{"topic": "machine learning", "style": "technical"}' > input.json # Invoke with file crewship invoke --input-file input.json ``` ### Wait for result ```bash theme={null} crewship invoke --input '{"query": "test"}' --wait ``` The CLI waits for completion and shows the final result: ``` ▶ Run started: run_abc123xyz ⏳ Waiting for completion... ✅ Run completed in 32.1s Result: { "output": "Generated report content...", "artifacts": ["report.md"] } ``` ### Invoke a named deployment ```bash theme={null} # In a multi-deployment project, target a specific deployment crewship invoke --name research-agent --input '{"topic": "AI agents"}' ``` ### Invoke specific deployment ```bash theme={null} # Invoke a previous deployment (for testing) crewship invoke --deployment dep_xyz789 --input '{"test": true}' ``` ## Input Format Input must be valid JSON: ```bash theme={null} # Object crewship invoke --input '{"key": "value"}' # With nested data crewship invoke --input '{"user": {"name": "Alice", "preferences": ["fast", "detailed"]}}' ``` Your crew receives this as the `inputs` parameter: ```python theme={null} def kickoff(inputs: dict): topic = inputs.get("key") user_name = inputs.get("user", {}).get("name") ``` ## Event Types When streaming, you'll see these event types: | Event | Description | | --------------------- | ------------------- | | `▶ Run started` | Run execution began | | `├─ [time] message` | Log from your crew | | `├─ Tool: name(args)` | Tool was invoked | | `├─ Artifact: name` | File was produced | | `✅ Run completed` | Success | | `❌ Run failed` | Error occurred | ## Handling Errors If a run fails: ```bash theme={null} crewship invoke --input '{"bad": "input"}' --stream ``` ``` ▶ Run started: run_abc123xyz ├─ [10:30:01] Starting crew execution... ├─ [10:30:02] Error: Missing required field 'topic' ❌ Run failed after 1.2s Error: CrewExecutionError: Missing required field 'topic' ``` ## Programmatic Usage For scripts and automation: ```bash theme={null} # Get run ID RUN_ID=$(crewship invoke --input '{"topic": "test"}' --json | jq -r '.run_id') # Poll for status crewship runs get $RUN_ID --json ``` ## Related Deep dive into event streaming Handle run outputs # CLI Overview Source: https://docs.crewship.dev/cli/overview The Crewship command-line interface for deploying and managing crews ## Installation Install the CLI with a single command: ```bash theme={null} curl -fsSL https://www.crewship.dev/install.sh | bash ``` This automatically detects your platform and installs the binary to `~/.local/bin`. Run this command in PowerShell: ```powershell theme={null} Invoke-WebRequest -Uri "https://api.crewship.dev/cli/releases/latest/download?platform=windows-x64" -OutFile "$env:LOCALAPPDATA\Programs\crewship.exe" ``` Then add the install location to your PATH: ```powershell theme={null} $path = [Environment]::GetEnvironmentVariable("Path", "User") if ($path -notlike "*$env:LOCALAPPDATA\Programs*") { [Environment]::SetEnvironmentVariable("Path", "$path;$env:LOCALAPPDATA\Programs", "User") } ``` Restart your terminal for the PATH change to take effect. Verify the installation: ```bash theme={null} crewship --version ``` ## Authentication Before using most commands, authenticate with your Crewship account: ```bash theme={null} crewship login ``` This opens a browser for authentication. Your credentials are stored securely in `~/.crewship/credentials.json`. ### Authentication commands | Command | Description | | ----------------- | ------------------------------- | | `crewship login` | Authenticate with Crewship | | `crewship logout` | Remove stored credentials | | `crewship whoami` | Show current authenticated user | ## Command Reference ### Project Setup | Command | Description | | ---------------------------- | --------------------------------- | | [`crewship init`](/cli/init) | Initialize a crewship.toml config | ### Deployment | Command | Description | | ----------------------------------------------- | ------------------------------ | | [`crewship deploy`](/cli/deploy) | Deploy your crew to production | | [`crewship deployment list`](/cli/deployment) | List all deployments | | [`crewship deployment delete`](/cli/deployment) | Delete a deployment | | [`crewship version list`](/cli/version) | List versions for a deployment | | [`crewship version delete`](/cli/version) | Delete a version | ### Environment | Command | Description | | ------------------------------- | ------------------------------ | | [`crewship env set`](/cli/env) | Set environment variables | | [`crewship env list`](/cli/env) | List all environment variables | | [`crewship env get`](/cli/env) | Get a specific variable | | [`crewship env rm`](/cli/env) | Remove environment variables | ### Execution | Command | Description | | -------------------------------- | ---------------------- | | [`crewship invoke`](/cli/invoke) | Run your deployed crew | ### Updates | Command | Description | | ---------------------------------- | ------------------------------------- | | [`crewship upgrade`](/cli/upgrade) | Update crewship to the latest version | ## Global Options These options are available for all commands: ```bash theme={null} crewship [command] --help # Show help for a command crewship [command] --version # Show CLI version crewship [command] --debug # Enable debug output ``` ### Multi-Deployment Support For projects with multiple deployments in a single `crewship.toml`, use `--name` / `-n` to target a specific deployment: ```bash theme={null} crewship deploy --name research-agent crewship invoke --name writer-agent --input '{"topic": "AI"}' crewship env set --name research-agent OPENAI_API_KEY=sk-... ``` See the [crewship.toml reference](/configuration/crewship-toml#multi-deployment) for configuration details. ## Configuration The CLI looks for configuration in this order: 1. Command-line flags 2. Environment variables (`CREWSHIP_*`) 3. Project config (`crewship.toml`) 4. User config (`~/.crewship/config.json`) ### Environment Variables | Variable | Description | | ------------------ | -------------------------------------------------- | | `CREWSHIP_API_URL` | Override API endpoint (for development) | | `CREWSHIP_TOKEN` | API token for CI/CD (instead of interactive login) | ## CI/CD Usage For automated deployments, use an API token instead of interactive login: ```bash theme={null} # Set token as environment variable export CREWSHIP_TOKEN=your_api_token # Deploy (no login required) crewship deploy ``` Generate API tokens in the [Console](https://console.crewship.dev) under Settings → API Keys. ## Exit Codes | Code | Meaning | | ---- | ----------------------- | | `0` | Success | | `1` | General error | | `2` | Invalid arguments | | `3` | Authentication required | | `4` | Network error | ## Next Steps Set up your project Deploy your crew List and delete deployments List and delete versions Manage secrets Run your crew # upgrade Source: https://docs.crewship.dev/cli/upgrade Update crewship to the latest version The `upgrade` command downloads and installs the latest version of the crewship CLI. ## Usage ```bash theme={null} crewship upgrade [options] ``` ## Options | Option | Description | | ------------- | ------------------------------------------------- | | `-f, --force` | Force reinstall even if already on latest version | | `-h, --help` | Show help message | ## How It Works The upgrade process: 1. **Check for updates** - Fetches the latest version information from the Crewship API 2. **Download** - Downloads the binary for your platform 3. **Verify** - Validates the SHA256 checksum to ensure integrity 4. **Backup** - Creates a backup of the current binary 5. **Install** - Replaces the current binary with the new version 6. **Cleanup** - Removes the backup after successful installation If anything goes wrong during installation, the original binary is automatically restored. ## Examples ### Check for and Install Updates ```bash theme={null} crewship upgrade ``` Output when an update is available: ``` Checking for updates... New version available: 0.2.0 (current: 0.1.0) Downloading crewship 0.2.0 for darwin-arm64... Verifying checksum... Checksum verified. Installing update... Successfully upgraded to crewship 0.2.0! ``` Output when already up to date: ``` Checking for updates... You are already running the latest version (0.2.0). ``` ### Force Reinstall Reinstall the latest version even if already up to date (useful for repairing a corrupted installation): ```bash theme={null} crewship upgrade --force ``` ## Automatic Update Notifications Crewship automatically checks for updates once per day when you run any command. If a new version is available, you'll see a notification: ``` ┌───────────────────────────────────────────────────────────┐ │ A new version of crewship is available: 0.2.0 │ │ You are currently running: 0.1.0 │ │ │ │ Run crewship upgrade to update │ └───────────────────────────────────────────────────────────┘ ``` This check is non-blocking and won't slow down your commands. The notification only appears once per new version. ## Security * **Checksum verification** - All downloads are verified against SHA256 checksums * **HTTPS** - All downloads use HTTPS encryption * **Atomic updates** - The update either completes fully or rolls back ## Troubleshooting ### Permission Denied If you get a permission error, the CLI may have been installed with elevated privileges: ```bash theme={null} sudo crewship upgrade ``` Or reinstall to a user-writable location: ```bash theme={null} curl -fsSL https://www.crewship.dev/install.sh | bash ``` ### Manual Update If automatic upgrade fails, download manually: ```bash theme={null} # macOS (Apple Silicon) curl -fsSL "https://api.crewship.dev/cli/releases/latest/download?platform=darwin-arm64" -o crewship chmod +x crewship mv crewship ~/.local/bin/ # macOS (Intel) curl -fsSL "https://api.crewship.dev/cli/releases/latest/download?platform=darwin-x64" -o crewship chmod +x crewship mv crewship ~/.local/bin/ # Linux curl -fsSL "https://api.crewship.dev/cli/releases/latest/download?platform=linux-x64" -o crewship chmod +x crewship mv crewship ~/.local/bin/ ``` ```powershell theme={null} Invoke-WebRequest -Uri "https://api.crewship.dev/cli/releases/latest/download?platform=windows-x64" -OutFile "$env:LOCALAPPDATA\Programs\crewship.exe" ``` # crewship version Source: https://docs.crewship.dev/cli/version List and delete versions for a deployment ## Overview Manage versions for your deployments. List all versions to see their status, or delete versions you no longer need. ## Commands ### List Versions ```bash theme={null} crewship version list [deployment-id] ``` If no deployment ID is provided, it is resolved from `crewship.toml`. Output: ``` Versions (3) v3 (production) ID: ver_abc123def456 Status: running Created: 1/22/2025, 3:00:00 PM v2 (production) ID: ver_xyz789ghi012 Status: stopped Created: 1/20/2025, 1:30:00 PM v1 (production) ID: ver_mno345pqr678 Status: stopped Created: 1/15/2025, 10:45:00 AM ``` ### Options for list | Option | Description | | --------------- | ------------------------------------------------ | | `--name`, `-n` | Deployment name (for multi-deployment configs) | | `--environment` | Filter by environment: `production` or `staging` | ### Delete a Version ```bash theme={null} crewship version delete ``` This soft-deletes the version. If the version was running, it will no longer receive new runs. Existing in-flight runs will complete normally. Deletion cannot be undone. ### Options for delete | Option | Description | | --------- | ------------------------ | | `--force` | Skip confirmation prompt | ## Examples ### List versions for a deployment ```bash theme={null} # By deployment ID crewship version list dep_abc123def456 # From crewship.toml crewship version list # For a named deployment crewship version list --name research-agent # Filter by environment crewship version list --environment production ``` ### Delete a version ```bash theme={null} crewship version delete ver_abc123def456 # Skip confirmation crewship version delete ver_abc123def456 --force ``` ## Related Manage deployments Deploy your crew # Core Concepts Source: https://docs.crewship.dev/concepts Understanding deployments, runs, artifacts, and the Crewship execution model ## Overview Crewship uses a simple but powerful execution model. Understanding these core concepts will help you get the most out of the platform. ## Deployments A **deployment** is an immutable snapshot of your crew at a point in time. Think of deployments like Git commits — each one captures a specific version of your code. ### What's in a deployment? * Your agent source code * Dependencies (Python: `requirements.txt` / `pyproject.toml`; JavaScript: `package.json`) * Crewship configuration (`crewship.toml`) * A container image built from the above ### Rollbacks Since deployments are immutable, rolling back is instant: ```bash theme={null} crewship deploy --rollback dep_xyz789 ``` ## Runs A **run** is a single execution of your crew. ### Run isolation Each run: * Gets its own container instance * Has no shared state with other runs * Is completely isolated * Scales to zero when complete ### Run inputs Pass data to your agent via the `input` parameter: ```bash theme={null} crewship invoke --input '{"topic": "quantum computing", "style": "blog"}' ``` Crewship passes this JSON object to your agent. How it's received depends on your framework: ```python CrewAI theme={null} def kickoff(inputs: dict): topic = inputs.get("topic") style = inputs.get("style") # ... ``` ```python LangGraph theme={null} # Input is passed as the initial graph state graph.invoke({"topic": "quantum computing", "style": "blog"}) ``` ```typescript LangGraph.js theme={null} // Input is passed as the initial graph state await graph.invoke({ topic: "quantum computing", style: "blog" }) ``` ## Artifacts **Artifacts** are files produced by your crew during a run. ### How artifacts work 1. Your crew writes files to `/app/artifacts/` 2. When the run completes, Crewship collects these files 3. Artifacts are stored durably and accessible via API ```python theme={null} # In your crew with open("/app/artifacts/report.md", "w") as f: f.write(generated_report) ``` ### Accessing artifacts ```bash CLI theme={null} # List artifacts crewship runs artifacts run_xyz789 # Download an artifact crewship runs download run_xyz789 report.md ``` ```bash cURL theme={null} # Get artifact download URL curl https://api.crewship.dev/v1/runs/run_xyz789/artifacts/report.md \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Common artifact types | Type | Extension | Use case | | --------- | --------------- | ---------------------------- | | Reports | `.md`, `.txt` | Generated content, summaries | | Data | `.json`, `.csv` | Structured output, datasets | | Documents | `.pdf`, `.docx` | Formatted documents | | Images | `.png`, `.jpg` | Generated visualizations | ## Events **Events** are structured messages emitted during a run. They enable real-time streaming and observability. ### Event types | Event | Description | | ----------------- | ------------------------- | | `run.started` | Run execution began | | `run.completed` | Run finished successfully | | `run.failed` | Run encountered an error | | `log` | Log message from the crew | | `artifact` | Artifact was produced | | `agent.started` | Agent began a task | | `agent.completed` | Agent finished a task | | `tool.called` | Tool was invoked | ### Streaming events Connect to the event stream via SSE: ```bash theme={null} curl -N https://api.crewship.dev/v1/runs/run_xyz789/events \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: text/event-stream" ``` Events arrive as they happen: ``` event: log data: {"message": "Researcher agent starting..."} event: agent.started data: {"agent": "Researcher", "task": "Research topic"} event: artifact data: {"name": "notes.md", "size": 1234} event: run.completed data: {"duration_ms": 45200} ``` ## Environment Variables Store secrets and configuration outside your code: ```bash theme={null} # Set a variable crewship env set OPENAI_API_KEY=sk-... # Variables are available in your crew import os api_key = os.environ["OPENAI_API_KEY"] ``` Never commit API keys or secrets to your repository. Use environment variables instead. ## Next Steps Master the Crewship CLI Customize your deployments # crewship.toml Source: https://docs.crewship.dev/configuration/crewship-toml Configure your crew deployment ## Overview The `crewship.toml` file configures how your crew is built and deployed. Place it in your project root. Crewship supports two formats: * **Single deployment** — one `[deployment]` section (default, created by `crewship init`) * **Multi-deployment** — multiple `[deployments.]` sections for monorepos with several agents Run [`crewship init`](/cli/init) to auto-generate this file with detected settings from your project. ## Single Deployment (default) ```toml crewship.toml theme={null} [deployment] framework = "crewai" entrypoint = "src.my_crew.crew:MyCrew" profile = "slim" python = "3.11" [build] exclude = ["tests"] ``` ```toml crewship.toml theme={null} [deployment] framework = "langgraph" entrypoint = "src.my_agent.graph:graph" profile = "slim" python = "3.11" [build] exclude = ["tests"] ``` ```toml crewship.toml theme={null} [deployment] framework = "langgraph-js" entrypoint = "./src/graph.ts:graph" profile = "slim" [build] exclude = ["tests"] ``` ## Multi-Deployment For monorepos with multiple agents sharing the same codebase, use named `[deployments.]` sections: ```toml crewship.toml theme={null} [build] exclude = ["tests"] [deployments.research-agent] framework = "crewai" entrypoint = "research_crew.crew:ResearchCrew" profile = "slim" python = "3.11" [deployments.writer-agent] framework = "crewai" entrypoint = "writer_crew.crew:WriterCrew" ``` Each named deployment gets its own deployment on Crewship with the name as the project name (e.g. `research-agent`). `[apis]` and `[chat]` can be set at the top level as global defaults, and overridden per deployment: ```toml crewship.toml theme={null} # Global defaults [chat] input_key = "query" [deployments.support-agent] framework = "crewai" entrypoint = "support_crew.crew:SupportCrew" [deployments.research-agent] framework = "crewai" entrypoint = "research_crew.crew:ResearchCrew" # Override chat config for this deployment only [deployments.research-agent.chat] input_key = "topic" ``` `[deployment]` and `[deployments.*]` are mutually exclusive. Using both in the same file will produce an error. ### Selecting a deployment Use `--name` / `-n` on any command to target a specific deployment: ```bash theme={null} crewship deploy --name research-agent crewship invoke --name writer-agent --input '{"topic": "AI"}' crewship env set --name research-agent OPENAI_API_KEY=sk-... ``` If `--name` is omitted: * **One named deployment** — auto-selected * **Multiple named deployments** — interactive prompt (or error in CI) * **Single `[deployment]` format** — used directly (no `--name` needed) ### Deployment IDs After the first deploy, `deployment_id` is saved into each section automatically: ```toml theme={null} [deployments.research-agent] framework = "crewai" entrypoint = "research_crew.crew:ResearchCrew" deployment_id = "dep_xxx1" # auto-populated [deployments.writer-agent] framework = "crewai" entrypoint = "writer_crew.crew:WriterCrew" deployment_id = "dep_xxx2" # auto-populated ``` ## Full Example ```toml crewship.toml theme={null} [deployment] framework = "crewai" entrypoint = "src.research_crew.crew:ResearchCrew" python = "3.11" profile = "slim" [build] exclude = ["tests"] [build.install] packages = ["ffmpeg", "imagemagick"] [apis] enabled = ["thread", "run"] [chat] input_key = "topic" [runtime] timeout = 600 memory = 512 [metadata] description = "A crew that researches topics and writes reports" tags = ["research", "writing"] ``` ## Configuration Reference ### \[deployment] / \[deployments.\] | Field | Type | Required | Description | | --------------- | ------ | -------- | ---------------------------------------------------------------- | | `framework` | string | ✅ | Framework to use: `crewai`, `langgraph`, or `langgraph-js` | | `entrypoint` | string | ✅ | Entry point for your agent (format varies by framework) | | `python` | string | `"3.11"` | Python version (`3.10`, `3.11`, `3.12`) — Python frameworks only | | `profile` | string | `"slim"` | Base image profile | | `dockerfile` | string | — | Custom Dockerfile path | | `deployment_id` | string | — | Auto-populated after first deploy | #### Entrypoint Format The entrypoint format depends on your framework: **CrewAI and LangGraph (Python)** — Python module path: ``` module.path:ClassName_or_variable ``` ```toml theme={null} # CrewAI: points to a class decorated with @CrewBase entrypoint = "src.my_crew.crew:MyCrew" # LangGraph: points to a compiled graph variable entrypoint = "src.my_agent.graph:graph" ``` **LangGraph.js** — file path relative to project root: ``` ./path/to/file.ts:exportName ``` ```toml theme={null} # LangGraph.js: points to an exported compiled graph entrypoint = "./src/graph.ts:graph" ``` Run `crewship init` to auto-detect your framework and entrypoint. For LangGraph projects, place a `langgraph.json` in your project root to enable auto-detection. #### Profile Options | Profile | Description | Frameworks | Use case | | --------- | ------------------------------ | --------------------- | ------------------------- | | `slim` | Minimal base environment | All | Most agents | | `browser` | Includes Playwright + Chromium | `crewai`, `langgraph` | Web scraping, screenshots | ### \[build] Build configuration options. | Field | Type | Default | Description | | --------- | --------------- | ------- | --------------------------- | | `exclude` | array of string | `[]` | Paths to exclude from build | ### \[build.install] Additional system packages to install. ```toml theme={null} [build.install] packages = ["ffmpeg", "poppler-utils", "tesseract-ocr"] ``` Only packages available in the base image's package manager (apt) are supported. ### \[runtime] Runtime configuration. | Field | Type | Default | Description | | --------- | ------- | ------- | ----------------------------- | | `timeout` | integer | `300` | Max execution time in seconds | | `memory` | integer | `256` | Memory limit in MB | ```toml theme={null} [runtime] timeout = 900 # 15 minutes memory = 1024 # 1 GB ``` ### \[apis] Controls which APIs are enabled for the deployment. This affects both direct API access and which interaction modes are available in [Slack](/guides/slack). | Field | Type | Default | Description | | --------- | --------------- | ------- | ----------------------------------------- | | `enabled` | array of string | — | Which APIs to expose: `"thread"`, `"run"` | When omitted (or `null`), **all APIs are enabled** by default. ```toml theme={null} [apis] enabled = ["thread", "run"] # Both APIs enabled (same as default) ``` ```toml theme={null} [apis] enabled = ["run"] # Only stateless runs — no thread/conversation support ``` ```toml theme={null} [apis] enabled = ["thread"] # Only threaded conversations — no standalone runs ``` In Slack, the enabled APIs determine which interaction modes work: * **Thread API** — `@mention` conversations use threads for multi-turn context * **Run API** — `/crewship run` slash commands use single stateless runs * If both are enabled, `@mention` defaults to thread mode Not sure which to use? Read [Runs vs Threads: When to Use Which](https://www.crewship.dev/blog/runs-vs-threads-when-to-use-which). ### \[chat] Configures how chat messages (from Slack or other integrations) map to your crew's input and output. | Field | Type | Default | Description | | ------------ | ------ | --------- | ---------------------------------------------------- | | `input_key` | string | `"input"` | The parameter name that receives the chat message | | `output_key` | string | — | Field in the run output containing response messages | ```toml theme={null} [chat] input_key = "topic" ``` When a user sends a message in Slack (e.g. "Tell me about quantum computing"), it gets mapped to: ```json theme={null} { "topic": "Tell me about quantum computing" } ``` If `output_key` is set, the platform extracts that field from the run result to display as the response: ```toml theme={null} [chat] input_key = "query" output_key = "messages" ``` If your crew already accepts an `input` parameter, you can omit `[chat]` entirely — it defaults to `input_key = "input"`. ### \[metadata] Optional metadata for organization. | Field | Type | Description | | ------------- | ------ | ----------------------------- | | `description` | string | Human-readable description | | `tags` | array | Tags for filtering in Console | ```toml theme={null} [metadata] description = "Researches topics and generates blog posts" tags = ["content", "blog", "research"] ``` ## Validation The CLI validates your `crewship.toml` on deploy: ```bash theme={null} crewship deploy ``` Common validation errors: ``` ❌ Error: Invalid crewship.toml - name: must be lowercase with hyphens only - deployment.entrypoint: required field missing ``` ## Environment-specific Config For different environments, use separate projects: ```bash theme={null} # Production crewship deploy --project my-crew # Staging crewship deploy --project my-crew-staging ``` Set different environment variables per project: ```bash theme={null} crewship env set OPENAI_API_KEY=sk-prod-... --project my-crew crewship env set OPENAI_API_KEY=sk-test-... --project my-crew-staging ``` ## Example Configurations ### Basic CrewAI ```toml theme={null} [deployment] framework = "crewai" entrypoint = "src.simple_crew.crew:SimpleCrew" ``` ### Basic LangGraph ```toml theme={null} [deployment] framework = "langgraph" entrypoint = "src.my_agent.graph:graph" python = "3.11" ``` ### Basic LangGraph.js ```toml theme={null} [deployment] framework = "langgraph-js" entrypoint = "./src/graph.ts:graph" ``` ### Web Scraping Crew ```toml theme={null} [deployment] framework = "crewai" entrypoint = "src.scraper.crew:ScraperCrew" profile = "browser" python = "3.11" [runtime] timeout = 600 memory = 1024 ``` ### Document Processing ```toml theme={null} [deployment] framework = "crewai" entrypoint = "src.processor.crew:ProcessorCrew" python = "3.11" [build.install] packages = ["poppler-utils", "tesseract-ocr"] [runtime] timeout = 900 memory = 2048 ``` ### Slack Chatbot ```toml theme={null} [deployment] framework = "crewai" entrypoint = "src.support_bot.flows.chat_flow:ChatFlow" python = "3.11" [apis] enabled = ["thread"] [chat] input_key = "query" output_key = "messages" ``` ### Multi-Agent Monorepo (mixed frameworks) ```toml theme={null} [build] exclude = ["tests", "notebooks"] [deployments.research-agent] framework = "crewai" entrypoint = "agents.research.crew:ResearchCrew" profile = "browser" python = "3.11" [deployments.writer-agent] framework = "langgraph" entrypoint = "agents.writer.graph:graph" python = "3.11" [deployments.frontend-agent] framework = "langgraph-js" entrypoint = "./agents/frontend/graph.ts:graph" ``` Deploy individual agents: ```bash theme={null} crewship deploy --name research-agent crewship deploy --name writer-agent ``` ## Related Deploy your configured crew Connect your crew to Slack Configure secrets Multi-turn conversations # Environment Variables Source: https://docs.crewship.dev/configuration/environment-variables Configure secrets and runtime settings for your crew ## Overview Environment variables allow you to: * Store API keys and secrets securely * Configure runtime behavior without code changes * Use different settings across environments ## Setting Variables ### Via CLI ```bash theme={null} crewship env set OPENAI_API_KEY=sk-proj-... ``` ### Via Console 1. Open the [Crewship Console](https://console.crewship.dev) 2. Navigate to your project 3. Go to **Settings** → **Environment Variables** 4. Click **Add Variable** ## Common Variables ### LLM API Keys ```bash theme={null} # OpenAI crewship env set OPENAI_API_KEY=sk-proj-... # Anthropic crewship env set ANTHROPIC_API_KEY=sk-ant-... # Google AI crewship env set GOOGLE_API_KEY=... # Azure OpenAI crewship env set AZURE_OPENAI_API_KEY=... crewship env set AZURE_OPENAI_ENDPOINT=https://... ``` ### Tool API Keys ```bash theme={null} # Web search (Serper) crewship env set SERPER_API_KEY=... # Browserless crewship env set BROWSERLESS_API_KEY=... # Firecrawl crewship env set FIRECRAWL_API_KEY=... ``` ### Custom Configuration ```bash theme={null} # Logging level crewship env set LOG_LEVEL=debug # Feature flags crewship env set ENABLE_CACHING=true # Custom settings crewship env set MAX_RETRIES=3 ``` ## Accessing in Code Variables are available as standard environment variables: ```python theme={null} import os # Direct access api_key = os.environ["OPENAI_API_KEY"] # With default log_level = os.environ.get("LOG_LEVEL", "info") # Check if set if os.environ.get("ENABLE_CACHING"): enable_cache() ``` ### CrewAI Integration CrewAI automatically uses standard environment variables: ```python theme={null} from crewai import Agent, LLM # Uses OPENAI_API_KEY automatically agent = Agent( role="Researcher", llm=LLM(model="gpt-4o") ) # Anthropic (uses ANTHROPIC_API_KEY) agent = Agent( role="Writer", llm=LLM(model="claude-3-5-sonnet-20241022") ) ``` ## Reserved Variables Crewship sets these automatically. They're read-only: | Variable | Description | | ------------------------ | ----------------------------- | | `CREWSHIP_RUN_ID` | Current run ID (`run_abc123`) | | `CREWSHIP_DEPLOYMENT_ID` | Deployment ID (`dep_xyz789`) | | `CREWSHIP_PROJECT` | Project name | | `CREWSHIP_ENVIRONMENT` | `production` or `preview` | Use them for logging and debugging: ```python theme={null} import os run_id = os.environ.get("CREWSHIP_RUN_ID") print(f"Starting run {run_id}") ``` ## Security ### Encryption All environment variables are: * **Encrypted at rest** using AES-256 * **Encrypted in transit** via TLS * **Never logged** in build or run output * **Access controlled** by project permissions ### Best Practices Add `.env` to `.gitignore`. Use `crewship env set` instead. Create API keys specific to Crewship. Easier to rotate and audit. Don't use fallback values for required secrets: ```python theme={null} # ❌ Bad - silently fails api_key = os.environ.get("API_KEY", "") # ✅ Good - fails immediately api_key = os.environ["API_KEY"] ``` List required variables in your README: ```markdown theme={null} ## Environment Variables - `OPENAI_API_KEY` - Required. OpenAI API key - `SERPER_API_KEY` - Required for web search - `LOG_LEVEL` - Optional. Default: info ``` ## Loading from .env For local development, use a `.env` file: ```text .env theme={null} OPENAI_API_KEY=sk-proj-... SERPER_API_KEY=... LOG_LEVEL=debug ``` Then load with `python-dotenv`: ```python theme={null} from dotenv import load_dotenv load_dotenv() ``` The `.env` file is **not** used in Crewship deployments. Always set production variables via `crewship env set`. ## Variable Scope Variables are scoped to **projects**, not deployments: ``` Project: my-crew ├── OPENAI_API_KEY = sk-... ├── SERPER_API_KEY = ... │ ├── Deployment: dep_abc (uses these vars) ├── Deployment: dep_xyz (uses these vars) └── All runs use these vars ``` ### Updating Variables Changes take effect immediately for new runs: ```bash theme={null} # Update a variable crewship env set OPENAI_API_KEY=sk-new-key-... # Next run uses new value (no redeploy needed) crewship invoke --input '{"topic": "test"}' ``` ## Environment Separation Use separate projects for different environments: ```bash theme={null} # Production crewship env set OPENAI_API_KEY=sk-prod-... --project my-crew crewship env set LOG_LEVEL=warning --project my-crew # Staging crewship env set OPENAI_API_KEY=sk-test-... --project my-crew-staging crewship env set LOG_LEVEL=debug --project my-crew-staging ``` ## Related Full CLI reference Project configuration # Artifacts Source: https://docs.crewship.dev/guides/artifacts Working with files and outputs from your crew runs ## Overview Artifacts are files produced by your crew during a run. Crewship automatically: * Collects files from a standard directory * Stores them durably * Makes them accessible via API and Console ## Producing Artifacts Write files to the `artifacts/` directory: ```python Python (CrewAI / LangGraph) theme={null} # Write files directly from your agent or node with open("artifacts/report.md", "w") as f: f.write(generated_content) ``` ```typescript TypeScript (LangGraph.js) theme={null} import { writeFileSync } from 'fs' import { mkdirSync } from 'fs' mkdirSync('artifacts', { recursive: true }) writeFileSync('artifacts/report.md', generatedContent) ``` With CrewAI, you can also use the `output_file` parameter on a task: ```yaml tasks.yaml theme={null} writing_task: description: Write a comprehensive report about {topic} expected_output: A detailed markdown report agent: writer output_file: artifacts/report.md ``` Produce as many files as needed: ```python theme={null} with open("artifacts/summary.md", "w") as f: f.write(summary) with open("artifacts/data.json", "w") as f: json.dump(data, f) with open("artifacts/chart.png", "wb") as f: f.write(image_bytes) ``` ## Accessing Artifacts ### Via CLI ```bash theme={null} # List artifacts for a run crewship runs artifacts run_xyz789 ``` Output: ``` Artifacts for run_xyz789: report.md 3.2 KB text/markdown data.json 1.1 KB application/json chart.png 45.6 KB image/png 3 artifacts, 49.9 KB total ``` Download artifacts: ```bash theme={null} # Download single artifact crewship runs download run_xyz789 report.md # Download all artifacts crewship runs download run_xyz789 --all # Download to specific directory crewship runs download run_xyz789 report.md --output ./downloads/ ``` ### Via API ```bash theme={null} # List artifacts curl https://api.crewship.dev/v1/runs/run_xyz789/artifacts \ -H "Authorization: Bearer YOUR_API_KEY" ``` Response: ```json theme={null} { "artifacts": [ { "name": "report.md", "size": 3276, "content_type": "text/markdown", "created_at": "2024-01-15T10:30:46Z" }, { "name": "data.json", "size": 1124, "content_type": "application/json", "created_at": "2024-01-15T10:30:46Z" } ] } ``` Download an artifact: ```bash theme={null} curl https://api.crewship.dev/v1/runs/run_xyz789/artifacts/report.md \ -H "Authorization: Bearer YOUR_API_KEY" \ -o report.md ``` ### Via Console 1. Open the [Console](https://console.crewship.dev) 2. Navigate to your run 3. Click the **Artifacts** tab 4. Click any artifact to preview or download ## Artifact Events When an artifact is produced, an event is emitted: ```json theme={null} { "type": "artifact", "payload": { "name": "report.md", "size": 3276, "content_type": "text/markdown", "sha256": "abc123..." } } ``` Use this for real-time notifications in streaming: ```bash theme={null} crewship invoke --input '{"topic": "AI"}' --stream # ... ├─ [10:30:46] Artifact: report.md (3.2 KB) ``` ## Supported File Types Any file type is supported. Common types include: | Type | Extensions | Use Case | | --------- | ---------------------- | ------------------- | | Text | `.md`, `.txt`, `.csv` | Reports, logs, data | | JSON | `.json` | Structured data | | Documents | `.pdf`, `.docx` | Formatted output | | Images | `.png`, `.jpg`, `.svg` | Charts, screenshots | | Archives | `.zip`, `.tar.gz` | Bundled outputs | ## Size Limits | Limit | Value | | --------------- | ------- | | Single artifact | 100 MB | | Total per run | 500 MB | | Retention | 30 days | Need larger limits? [Contact us](mailto:support@crewship.dev) for enterprise plans. ## Organizing Artifacts Use subdirectories for organization: ```python theme={null} with open("artifacts/reports/summary.md", "w") as f: f.write(summary) with open("artifacts/data/output.json", "w") as f: json.dump(data, f) ``` Artifacts are listed with their relative paths: ``` reports/summary.md 2.1 KB data/output.json 1.5 KB ``` ## Best Practices Name files clearly: `quarterly_report_2024Q1.md` not `output.md` Add timestamps or run info to filenames when helpful: ```python theme={null} filename = f"report_{run_id}_{timestamp}.md" ``` * Markdown for human-readable reports * JSON for structured data * CSV for tabular data * PDF for formatted documents For many files, create a zip archive: ```python theme={null} import zipfile with zipfile.ZipFile("artifacts/bundle.zip", "w") as zf: for file in files: zf.write(file) ``` ## Related Build a crew that produces artifacts Get notified when artifacts are produced # Building a Chatbot Source: https://docs.crewship.dev/guides/chatbot Build a multi-turn chatbot using CrewAI Flows and the Thread API ## Overview This guide walks through building a chatbot that maintains conversation history across multiple messages. It uses: * **CrewAI Flows** to manage conversation state * **Threads** to persist state between runs * The **Thread API** (or [Slack](/guides/slack)) for multi-turn interaction ## Project Structure ``` my-chatbot/ src/ my_chatbot/ agents/ chat_agent.py suggest_agent.py flows/ chat_flow.py crewship.toml pyproject.toml ``` ## Step 1: Define the Chat Agent Create an agent that responds to user messages given conversation history: ```python src/my_chatbot/agents/chat_agent.py theme={null} from crewai import Agent, LLM llm = LLM(model="openrouter/anthropic/claude-sonnet-4") chat_agent = Agent( role="Helpful Assistant", goal="Assist users by answering their questions clearly and helpfully", backstory=( "You are a friendly and knowledgeable assistant. You provide clear, " "concise, and helpful responses to user questions." ), llm=llm, respect_context_window=True, verbose=False, ) ``` Optionally, add a second agent that suggests follow-up questions: ```python src/my_chatbot/agents/suggest_agent.py theme={null} from crewai import Agent, LLM llm = LLM(model="openrouter/anthropic/claude-sonnet-4") suggest_agent = Agent( role="Follow-up Question Generator", goal="Generate 3 relevant follow-up questions based on a conversation", backstory=( "You analyze conversations and suggest exactly 3 brief follow-up " "questions the user might want to ask next. Return only the 3 questions, " "one per line, without numbering or bullet points." ), llm=llm, respect_context_window=True, verbose=False, ) ``` ## Step 2: Create the Chat Flow The flow manages conversation state — it appends each user message and assistant response to a `messages` list that persists across runs via thread state: ```python src/my_chatbot/flows/chat_flow.py theme={null} from crewai.flow.flow import Flow, listen, start from pydantic import BaseModel from my_chatbot.agents.chat_agent import chat_agent from my_chatbot.agents.suggest_agent import suggest_agent class ChatState(BaseModel): query: str = "" messages: list[dict] = [] suggested_questions: list[str] = [] class ChatFlow(Flow[ChatState]): @start() def chat(self): """Add the user query to messages, call the agent, and return the response.""" user_msg = {"role": "user", "content": self.state.query} history = self.state.messages + [user_msg] result = chat_agent.kickoff(history) assistant_msg = {"role": "assistant", "content": result.raw} self.state.messages = self.state.messages + [user_msg, assistant_msg] return result.raw @listen(chat) def suggest(self, chat_response: str): """Generate 3 follow-up questions based on the conversation.""" recent = self.state.messages[-6:] conversation = "\n".join(f"{m['role']}: {m['content']}" for m in recent) result = suggest_agent.kickoff( f"Based on this conversation, suggest exactly 3 brief follow-up questions " f"the user might want to ask next. Return only the 3 questions, one per line, " f"without numbering or bullet points.\n\n{conversation}" ) questions = [q.strip() for q in result.raw.strip().split("\n") if q.strip()][:3] self.state.suggested_questions = questions return { "messages": self.state.messages, "suggested_questions": self.state.suggested_questions, } ``` **How state works:** When running inside a thread, Crewship passes the previous thread state (including `messages`) into the flow. The flow appends the new exchange and returns the updated state, which Crewship saves as a checkpoint. ## Step 3: Configure crewship.toml ```toml crewship.toml theme={null} [deployment] framework = "crewai" entrypoint = "my_chatbot.flows.chat_flow:ChatFlow" python = "3.11" [chat] input_key = "query" output_key = "messages" ``` * `input_key = "query"` — maps incoming messages to the `query` field in `ChatState` * `output_key = "messages"` — tells integrations (like Slack) to extract the `messages` field from the output ## Step 4: Deploy ```bash theme={null} crewship deploy ``` ## Using the Chatbot ### Via the Thread API Create a thread and send messages to it: ```bash theme={null} # Create a thread curl -X POST https://api.crewship.dev/v1/threads \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"deployment_id": "dep_abc123"}' # Returns: {"thread_id": "thr_xyz789", ...} # Send first message curl -X POST https://api.crewship.dev/v1/threads/thr_xyz789/runs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"input": {"query": "What are AI agents?"}}' # Send follow-up (thread state carries conversation history) curl -X POST https://api.crewship.dev/v1/threads/thr_xyz789/runs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"input": {"query": "How do they differ from simple chatbots?"}}' ``` Each run in the thread receives the accumulated `messages` from previous runs, so the agent has full conversation context. ### Via the CLI ```bash theme={null} # Create a thread crewship thread create dep_abc123 # Chat in the thread crewship invoke dep_abc123 --thread thr_xyz789 -i '{"query": "What are AI agents?"}' crewship invoke dep_abc123 --thread thr_xyz789 -i '{"query": "How do they differ from simple chatbots?"}' ``` ### Via Slack Once you've [connected Slack](/guides/slack) and set this deployment as the default, users can simply mention the bot: ``` @MyBot What are AI agents? ``` Replies in the same Slack thread automatically continue the conversation — Crewship maps each Slack thread to a Crewship thread behind the scenes. ## Related Thread concepts and management Connect your chatbot to Slack Stream responses in real time Thread API reference # Runs vs. threads Source: https://docs.crewship.dev/guides/runs-vs-threads When to use stateless runs and when to use stateful threads Crewship has two execution modes: **runs** and **threads**. Every deployment supports both out of the box. ## Runs A run is a single, stateless execution of your crew. You send input, the crew does its work, you get output. Each run is isolated — it shares nothing with other runs and has no memory of previous executions. ```bash theme={null} curl -X POST https://api.crewship.dev/v1/runs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"deployment_id": "dep_abc123", "input": {"topic": "AI agents"}}' ``` A run moves through `pending`, `running`, then lands on `succeeded`, `failed`, or `canceled`. You can [stream events](/guides/streaming) in real time or poll for the result. Use runs when: * The task is self-contained (write a report, analyze a dataset, process a batch) * The crew doesn't need context from previous executions * You want to fire off many executions in parallel * The workload is triggered by a webhook, cron, or automated pipeline ## Threads A thread is a persistent conversation context scoped to a deployment. You create a thread once, then run your crew inside it multiple times. Each run receives the thread's current state, and when it finishes, the state updates. The next run picks up where the last one left off. ```bash theme={null} # Create a thread curl -X POST https://api.crewship.dev/v1/threads \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"deployment_id": "dep_abc123"}' # Run inside it curl -X POST https://api.crewship.dev/v1/threads/thr_xyz789/runs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"input": {"message": "Research AI agents in healthcare"}}' # Follow up — the crew remembers the first message curl -X POST https://api.crewship.dev/v1/threads/thr_xyz789/runs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"input": {"message": "Now focus on diagnostic applications"}}' ``` Only one run can execute in a thread at a time. If a run is already in progress, new requests return a `409 Conflict`. Use threads when: * Users interact with the crew multiple times per session (chatbots, support agents) * The crew's output depends on conversation history, not just the current input * You need iterative refinement ("generate a plan", then "make the budget more detailed") * Multi-step workflows require human review between steps ## Quick comparison | | Runs | Threads | | ----------- | -------------------------------- | --------------------------------------- | | State | None — each run is isolated | Persistent across runs via `values` | | Lifecycle | `pending` → `running` → terminal | `idle` → `busy` → `idle` (repeats) | | Concurrency | Unlimited parallel runs | One run at a time per thread | | History | Individual run records | Checkpoints after each run | | Setup | None — just create a run | Create thread first, then run inside it | ## The short version Does the crew need to remember anything from previous executions? If no, use a run. If yes, use a thread. Trying to fake statefulness by stuffing prior context into run inputs gets messy fast, and you lose checkpoints, history, and the concurrency guarantees that threads provide. ## Further reading * [Threads guide](/guides/threads) for thread state, checkpoints, metadata, and lifecycle details * [Building a chatbot](/guides/chatbot) for a full walkthrough using threads with CrewAI Flows * [Runs API reference](/api-reference/runs/create) * [Threads API reference](/api-reference/threads/create) # Slack Integration Source: https://docs.crewship.dev/guides/slack Connect your crews to Slack so users can interact with them via mentions and slash commands ## Overview Crewship can connect your deployments directly to Slack, allowing users to interact with your crews through `@mentions` and `/crewship` slash commands in any channel. **How it works:** 1. You create a Slack app and connect it to your Crewship organization 2. Configure which deployment to invoke and how messages map to crew inputs 3. Users interact with your crew in Slack — the platform handles message routing, input mapping, and response delivery ## Setting Up ### 1. Create a Slack App Go to **Settings > Integrations** in the [Crewship Console](https://console.crewship.dev) and click **Connect to Slack**. You'll be guided through a setup flow: 1. **Configure your app** — Choose a name for your Slack app and bot display name 2. **Create the app in Slack** — Click the link to create a pre-configured Slack app with the correct scopes and event subscriptions 3. **Enter credentials** — Copy the **Client ID**, **Client Secret**, and **Signing Secret** from your Slack app's Basic Information page 4. **Authorize** — Complete the OAuth flow to install the app in your workspace ### 2. Set a Default Deployment After connecting, select a **default deployment** from the dropdown next to your workspace. This is the crew that will be invoked when users `@mention` the bot without specifying a deployment name. ### 3. Configure Chat Mapping In your `crewship.toml`, add a `[chat]` section to control how Slack messages are passed to your crew: ```toml crewship.toml theme={null} [deployment] framework = "crewai" entrypoint = "src.support_bot.crew:SupportCrew" [chat] input_key = "query" output_key = "messages" ``` Then redeploy: ```bash theme={null} crewship deploy ``` See the [`[chat]` reference](/configuration/crewship-toml#chat) for all options. ## Interaction Modes ### @Mentions (Thread API) When a user mentions your bot in a channel, it starts a threaded conversation: ``` @Crewship What's our refund policy? ``` * Creates a Crewship [thread](/guides/threads) behind the scenes * Replies in the same Slack thread maintain conversation context * Each follow-up message in the thread sends a new run with the full thread state Requires the **Thread API** to be enabled on the deployment (enabled by default). ### Slash Commands (Run API) The `/crewship` slash command runs a single stateless execution: ``` /crewship run my-deployment What are the top trends in AI? ``` Format: `/crewship run ` Slash commands also support **JSON passthrough** — if the input is a valid JSON object, it's passed directly to the crew without wrapping: ``` /crewship run my-deployment {"topic": "AI trends", "format": "bullet-points"} ``` Requires the **Run API** to be enabled on the deployment (enabled by default). ## Controlling Enabled APIs Use `[apis]` in your `crewship.toml` to control which interaction modes are available: ```toml theme={null} [apis] enabled = ["thread"] # Only @mentions — disable slash command runs ``` ```toml theme={null} [apis] enabled = ["run"] # Only slash commands — disable threaded mentions ``` When omitted, both APIs are enabled by default. See the [`[apis]` reference](/configuration/crewship-toml#apis) for details. ## Input and Output Mapping ### Input When a Slack message arrives, it's wrapped into a JSON object using your `chat.input_key`: | Message | `input_key` | Crew receives | | ------------------ | ------------------- | ------------------------------- | | "Tell me about AI" | `"input"` (default) | `{"input": "Tell me about AI"}` | | "Tell me about AI" | `"topic"` | `{"topic": "Tell me about AI"}` | ### Output If `chat.output_key` is set, the platform extracts that field from the run result to post back to Slack. If not set, the full run output is used as the response. ## Example Configuration A complete setup for a Slack-enabled customer support bot: ```toml crewship.toml theme={null} [deployment] framework = "crewai" entrypoint = "src.support_bot.flows.chat_flow:ChatFlow" python = "3.11" [apis] enabled = ["thread"] [chat] input_key = "query" output_key = "messages" [runtime] timeout = 120 ``` ## Managing Workspaces In **Settings > Integrations**, you can: * **Enable/disable** a workspace connection without removing it * **Change the default deployment** at any time * **Disconnect** a workspace entirely ## Related Chat input/output mapping reference API enablement reference Multi-turn conversation context Build a thread-based chatbot # Streaming Source: https://docs.crewship.dev/guides/streaming Real-time event streaming from your crew runs ## Overview Crewship provides real-time event streaming so you can: * Monitor crew execution as it happens * Build responsive UIs that update live * Debug issues by watching the event flow * Log events to external systems ## Streaming via CLI The simplest way to stream events: ```bash theme={null} crewship invoke --input '{"topic": "AI"}' --stream ``` Output updates in real-time: ``` ▶ Run started: run_abc123 ├─ [10:30:01] Starting crew execution ├─ [10:30:02] Researcher agent starting task ├─ [10:30:05] Tool: web_search("AI agents 2024") ├─ [10:30:12] Researcher agent completed task ├─ [10:30:13] Writer agent starting task ├─ [10:30:45] Writer agent completed task ├─ [10:30:46] Artifact: report.md ✅ Run completed in 45.2s ``` ## Streaming via API ### Server-Sent Events (SSE) Connect to the events endpoint with SSE: ```bash theme={null} curl -N \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Accept: text/event-stream" \ "https://api.crewship.dev/v1/runs/run_abc123/events" ``` ### JavaScript/TypeScript ```typescript theme={null} const eventSource = new EventSource('https://api.crewship.dev/v1/runs/run_abc123/events', { headers: { Authorization: 'Bearer YOUR_API_KEY', }, }) eventSource.onmessage = (event) => { const data = JSON.parse(event.data) console.log(data.type, data.payload) } eventSource.onerror = (error) => { console.error('Stream error:', error) eventSource.close() } ``` ### Python ```python theme={null} import requests response = requests.get( "https://api.crewship.dev/v1/runs/run_abc123/events", headers={ "Authorization": "Bearer YOUR_API_KEY", "Accept": "text/event-stream" }, stream=True ) for line in response.iter_lines(): if line: # Parse SSE format if line.startswith(b"data: "): data = json.loads(line[6:]) print(data["type"], data["payload"]) ``` ## Event Types ### Run Lifecycle Events | Event | Description | Payload | | --------------- | ---------------- | --------------------------------- | | `run.started` | Execution began | `{ run_id, started_at }` | | `run.completed` | Success | `{ run_id, duration_ms, result }` | | `run.failed` | Error | `{ run_id, error, stack_trace }` | | `run.canceled` | Manually stopped | `{ run_id, canceled_at }` | ### Agent Events | Event | Description | Payload | | ----------------- | ---------------- | ------------------------- | | `agent.started` | Agent began task | `{ agent, task }` | | `agent.completed` | Agent finished | `{ agent, task, output }` | | `agent.error` | Agent failed | `{ agent, error }` | ### Tool Events | Event | Description | Payload | | ------------- | ------------- | ------------------ | | `tool.called` | Tool invoked | `{ tool, input }` | | `tool.result` | Tool returned | `{ tool, output }` | | `tool.error` | Tool failed | `{ tool, error }` | ### Log Events | Event | Description | Payload | | ----- | ----------- | ------------------------------- | | `log` | Log message | `{ level, message, timestamp }` | ### Artifact Events | Event | Description | Payload | | ---------- | ------------- | ------------------------------ | | `artifact` | File produced | `{ name, size, content_type }` | ## Event Format Each SSE event follows this format: ``` event: data: id: ``` Example: ``` event: agent.started data: {"agent":"Researcher","task":"Research AI trends","timestamp":"2024-01-15T10:30:02Z"} id: evt_001 event: tool.called data: {"tool":"web_search","input":"AI agents 2024","timestamp":"2024-01-15T10:30:05Z"} id: evt_002 event: log data: {"level":"info","message":"Found 15 relevant results","timestamp":"2024-01-15T10:30:06Z"} id: evt_003 ``` ## Reconnection SSE supports automatic reconnection. Use the `Last-Event-ID` header: ```javascript theme={null} let lastEventId = localStorage.getItem('lastEventId') const eventSource = new EventSource(`https://api.crewship.dev/v1/runs/${runId}/events`, { headers: { Authorization: `Bearer ${apiKey}`, 'Last-Event-ID': lastEventId || '', }, }) eventSource.onmessage = (event) => { localStorage.setItem('lastEventId', event.lastEventId) // Process event... } ``` ## Building a Live UI Example React component: ```tsx theme={null} function RunProgress({ runId }: { runId: string }) { const [events, setEvents] = useState([]) const [status, setStatus] = useState<'running' | 'completed' | 'failed'>('running') useEffect(() => { const eventSource = new EventSource(`https://api.crewship.dev/v1/runs/${runId}/events`) eventSource.onmessage = (event) => { const data = JSON.parse(event.data) setEvents((prev) => [...prev, data]) if (data.type === 'run.completed') { setStatus('completed') eventSource.close() } else if (data.type === 'run.failed') { setStatus('failed') eventSource.close() } } return () => eventSource.close() }, [runId]) return (
) } ``` ## Filtering Events Request specific event types: ```bash theme={null} curl -N \ -H "Authorization: Bearer YOUR_API_KEY" \ "https://api.crewship.dev/v1/runs/run_abc123/events?types=agent.started,agent.completed,artifact" ``` ## Related Trigger runs and receive notifications CLI streaming options Events API docs # Threads Source: https://docs.crewship.dev/guides/threads Maintain conversation context across multiple runs with threads ## What are Threads? Threads allow you to maintain stateful conversation context across multiple runs within a deployment. Each thread is scoped to a single deployment and tracks conversation history, state, and checkpoints. This is modeled after LangGraph's Threads API and works with CrewAI, LangGraph Python, and LangGraph JS frameworks. ## Key Concepts * **Thread**: A stateful conversation context scoped to a deployment * **Thread State**: JSON values representing the current conversation state * **Checkpoints**: Historical snapshots of thread state after each run * **Thread Status**: `idle` (ready), `busy` (running), `interrupted`, or `error` ## Creating a Thread ```bash cURL theme={null} curl -X POST https://api.crewship.dev/v1/threads \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "deployment_id": "dep_abc123", "metadata": {"user_id": "user_1", "session": "chat"} }' ``` ```bash CLI theme={null} crewship thread create dep_abc123 --metadata '{"user_id": "user_1"}' ``` ## Running in a Thread When you create a run in a thread context, the runner receives the thread state and can update it after completion. ```bash cURL theme={null} curl -X POST https://api.crewship.dev/v1/threads/thr_abc123/runs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": {"message": "Hello, how are you?"} }' ``` ```bash CLI theme={null} crewship invoke dep_abc123 --thread thr_abc123 -i '{"message": "Hello"}' ``` ## Concurrency Only one run can execute in a thread at a time. If a thread is `busy`, new run requests will be rejected with a 409 status. Wait for the current run to complete before starting a new one. ## Thread History Each run that updates thread state creates a checkpoint. You can view the history of state changes: ```bash theme={null} curl https://api.crewship.dev/v1/threads/thr_abc123/history \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Managing Threads ```bash theme={null} # List threads for a deployment crewship thread list dep_abc123 # Get thread details crewship thread get thr_abc123 # Copy a thread (duplicate state) crewship thread copy thr_abc123 # Delete a thread crewship thread delete thr_abc123 ``` ## Related Real-time event streaming from runs Threads API docs # Webhooks Source: https://docs.crewship.dev/guides/webhooks Trigger runs and receive notifications via webhooks ## Overview Crewship webhooks let you: * **Incoming webhooks**: Trigger runs via HTTP POST requests from external systems * **Outgoing webhooks**: Receive notifications when runs complete ## Incoming Webhooks Incoming webhooks provide unique URLs that trigger runs when called. Use them to integrate with: * CI/CD pipelines (GitHub Actions, GitLab CI, etc.) * Scheduling services (cron jobs, cloud schedulers) * No-code automation tools (Zapier, Make, n8n) * Custom integrations ### Creating an Incoming Webhook 1. Go to your deployment in the [Console](https://console.crewship.dev) 2. Click **Webhooks** 3. Click **Add Incoming Webhook** 4. Enter a name and select the environment (production/staging) 5. Copy the generated webhook URL ### Triggering a Run Send a POST request to the webhook URL with your run input: ```bash theme={null} curl -X POST "https://api.crewship.dev/webhooks/runs/YOUR_WEBHOOK_TOKEN" \ -H "Content-Type: application/json" \ -d '{"topic": "AI agents", "year": "2025"}' ``` **Response (202 Accepted):** ```json theme={null} { "run_id": "run_abc123", "version_id": "ver_xyz789", "version_number": 5, "status": "running" } ``` The webhook waits for the run to start before returning, so a `202` response means the run is actually executing. ### Example: GitHub Actions Trigger a crew run on every push to main: ```yaml theme={null} name: Run Crew on: push: branches: [main] jobs: run-crew: runs-on: ubuntu-latest steps: - name: Trigger Crewship Run run: | curl -X POST "${{ secrets.CREWSHIP_WEBHOOK_URL }}" \ -H "Content-Type: application/json" \ -d '{"commit": "${{ github.sha }}", "branch": "${{ github.ref_name }}"}' ``` ### Example: Scheduled Runs Use a cron service or cloud scheduler to trigger runs on a schedule: ```bash theme={null} # Daily at 9am UTC via cron 0 9 * * * curl -X POST "https://api.crewship.dev/webhooks/runs/YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"date": "$(date +%Y-%m-%d)"}' ``` ## Outgoing Webhooks Outgoing webhooks notify external systems when runs complete. Use them to: * Send Slack/Discord notifications * Update databases or dashboards * Trigger downstream workflows * Log results to external systems ### Creating an Outgoing Webhook 1. Go to your deployment in the [Console](https://console.crewship.dev) 2. Click **Webhooks** 3. Click **Add Outgoing Webhook** 4. Enter a name, target URL, and select events 5. Save the signing secret securely ### Events | Event | Description | | --------------- | -------------------------- | | `run.succeeded` | Run completed successfully | | `run.failed` | Run failed with an error | ### Webhook Payload When a run completes, Crewship sends a POST request to your URL: ```json theme={null} { "event": "run.succeeded", "timestamp": "2025-01-15T10:30:00.000Z", "data": { "run_id": "run_abc123", "deployment_id": "dep_xyz789", "status": "succeeded", "output": { "result": "Your crew output here..." }, "started_at": "2025-01-15T10:29:15.000Z", "completed_at": "2025-01-15T10:30:00.000Z" } } ``` ### Security Headers Every outgoing webhook request includes these headers: | Header | Description | | ---------------------- | -------------------------------------- | | `X-Crewship-Event` | Event type (e.g., `run.succeeded`) | | `X-Crewship-Delivery` | Unique delivery ID for debugging | | `X-Crewship-Timestamp` | Unix timestamp when request was signed | | `X-Crewship-Signature` | HMAC-SHA256 signature for verification | ### Verifying Signatures Always verify webhook signatures to ensure requests are from Crewship: ```typescript theme={null} import crypto from 'crypto' function verifyWebhookSignature( secret: string, timestamp: string, body: string, signature: string ): boolean { const signedPayload = `${timestamp}.${body}` const expectedSignature = crypto .createHmac('sha256', secret) .update(signedPayload) .digest('hex') return signature === `sha256=${expectedSignature}` } // In your webhook handler app.post('/webhook', (req, res) => { const timestamp = req.headers['x-crewship-timestamp'] const signature = req.headers['x-crewship-signature'] const body = JSON.stringify(req.body) if (!verifyWebhookSignature(WEBHOOK_SECRET, timestamp, body, signature)) { return res.status(401).send('Invalid signature') } // Process the webhook... const { event, data } = req.body console.log(`Run ${data.run_id} ${event}`) res.status(200).send('OK') }) ``` ### Python Example ```python theme={null} import hmac import hashlib def verify_webhook_signature(secret: str, timestamp: str, body: str, signature: str) -> bool: signed_payload = f"{timestamp}.{body}" expected = hmac.new( secret.encode(), signed_payload.encode(), hashlib.sha256 ).hexdigest() return signature == f"sha256={expected}" # In your Flask handler @app.route('/webhook', methods=['POST']) def webhook(): timestamp = request.headers.get('X-Crewship-Timestamp') signature = request.headers.get('X-Crewship-Signature') body = request.get_data(as_text=True) if not verify_webhook_signature(WEBHOOK_SECRET, timestamp, body, signature): return 'Invalid signature', 401 data = request.json print(f"Run {data['data']['run_id']} {data['event']}") return 'OK', 200 ``` ### Delivery Logs View delivery attempts in the Console: 1. Go to your deployment → **Webhooks** 2. Find your outgoing webhook 3. Click **Deliveries** Each delivery shows: * Status (succeeded/failed) * HTTP response code * Error message (if failed) * Timestamp ## Managing Webhooks ### Regenerating Secrets If your webhook secret is compromised: 1. Go to your webhook in the Console 2. Click **Regenerate Secret** 3. Update your integration with the new secret The old secret stops working immediately. Update your integration before regenerating. ### Disabling Webhooks Toggle the **Enabled** switch to temporarily disable a webhook without deleting it. ### Environment Filtering Webhooks are scoped to an environment (production or staging). Create separate webhooks if you need different behavior per environment. ## Best Practices Never process outgoing webhooks without verifying the signature. This prevents attackers from sending fake webhook payloads. Return a 2xx response within 30 seconds. Crewship waits for your response before marking the delivery as complete. Use the `X-Crewship-Delivery` header to deduplicate. In rare cases, the same event may be delivered twice. Store webhook secrets in environment variables or a secrets manager. Never commit them to version control. ## Testing Webhooks Use [webhook.site](https://webhook.site) to test outgoing webhooks: 1. Go to webhook.site and copy your unique URL 2. Create an outgoing webhook with that URL 3. Trigger a run 4. View the payload on webhook.site ## Related Real-time event streaming via SSE Create runs via API # Your First CrewAI Crew Source: https://docs.crewship.dev/guides/your-first-crew Build and deploy a complete CrewAI crew from scratch ## What We'll Build A research crew that: 1. Researches a topic using web search 2. Analyzes and synthesizes findings 3. Produces a written report as an artifact ## Prerequisites * Python 3.11+ * CrewAI installed (`pip install crewai`) * Crewship CLI installed and authenticated Want to skip the setup? Clone the [crewai-quickstart](https://github.com/Crewship/crewai-quickstart) repo and run `crewship deploy` to get a working crew deployed in minutes. ## Step 1: Create the Project ```bash theme={null} # Create a new CrewAI project crewai create crew research_crew cd research_crew ``` This creates: ``` research_crew/ ├── src/ │ └── research_crew/ │ ├── __init__.py │ ├── crew.py │ ├── main.py │ └── config/ │ ├── agents.yaml │ └── tasks.yaml ├── pyproject.toml └── README.md ``` ## Step 2: Define Your Agents Edit `src/research_crew/config/agents.yaml`: ```yaml agents.yaml theme={null} researcher: role: Senior Research Analyst goal: > Uncover cutting-edge developments and insights about {topic} backstory: > You're a seasoned research analyst with a keen eye for emerging trends. You excel at finding and synthesizing information from diverse sources. tools: - SerperDevTool writer: role: Technical Content Writer goal: > Create engaging, well-structured content about {topic} backstory: > You're an experienced technical writer who transforms complex research into clear, compelling narratives. You write for a technical audience. ``` ## Step 3: Define Your Tasks Edit `src/research_crew/config/tasks.yaml`: ```yaml tasks.yaml theme={null} research_task: description: > Research the topic: {topic} Find the latest developments, key players, challenges, and future trends. Focus on credible sources and recent information. expected_output: > A comprehensive research brief with key findings, sources, and insights. agent: researcher writing_task: description: > Write a detailed report based on the research about {topic}. Structure: 1. Executive Summary 2. Key Findings 3. Analysis 4. Future Outlook 5. Sources expected_output: > A well-structured markdown report of 800-1200 words. agent: writer output_file: artifacts/report.md ``` Files written to `artifacts/` are collected as run artifacts, accessible via the API and Console. ## Step 4: Configure the Crew Edit `src/research_crew/crew.py`: ```python crew.py theme={null} from crewai import Agent, Crew, Process, Task from crewai.project import CrewBase, agent, crew, task from crewai_tools import SerperDevTool @CrewBase class ResearchCrew: """Research crew that produces written reports""" agents_config = "config/agents.yaml" tasks_config = "config/tasks.yaml" @agent def researcher(self) -> Agent: return Agent( config=self.agents_config["researcher"], tools=[SerperDevTool()], verbose=True, ) @agent def writer(self) -> Agent: return Agent( config=self.agents_config["writer"], verbose=True, ) @task def research_task(self) -> Task: return Task(config=self.tasks_config["research_task"]) @task def writing_task(self) -> Task: return Task(config=self.tasks_config["writing_task"]) @crew def crew(self) -> Crew: return Crew( agents=self.agents, tasks=self.tasks, process=Process.sequential, verbose=True, ) ``` ## Step 5: Create the Entry Point Edit `src/research_crew/main.py`: ```python main.py theme={null} from research_crew.crew import ResearchCrew def kickoff(inputs: dict) -> str: """Entry point for Crewship deployment""" crew = ResearchCrew() result = crew.crew().kickoff(inputs=inputs) return str(result) # For local testing if __name__ == "__main__": result = kickoff({"topic": "AI agents in 2024"}) print(result) ``` ## Step 6: Add Dependencies Ensure `pyproject.toml` includes required packages: ```toml pyproject.toml theme={null} [project] name = "research_crew" version = "0.1.0" requires-python = ">=3.11" dependencies = [ "crewai>=0.80.0", "crewai-tools>=0.14.0", ] ``` ## Step 7: Add Crewship Configuration Create `crewship.toml` in the project root: ```toml crewship.toml theme={null} name = "research-crew" framework = "crewai" [build] entrypoint = "research_crew.main:kickoff" python = "3.11" [runtime] timeout = 600 memory = 512 [metadata] description = "A crew that researches topics and writes reports" tags = ["research", "writing"] ``` ## Step 8: Set Environment Variables ```bash theme={null} # OpenAI for the LLM crewship env set OPENAI_API_KEY=sk-proj-... # Serper for web search crewship env set SERPER_API_KEY=... ``` ## Step 9: Deploy ```bash theme={null} crewship deploy ``` ``` 📦 Packaging crew... ☁️ Uploading build context... 🔨 Building image... ✅ Deployed successfully! Deployment: dep_abc123xyz Project: research-crew ``` ## Step 10: Run Your Crew ```bash theme={null} crewship invoke --input '{"topic": "quantum computing in 2024"}' --stream ``` Watch the execution: ``` ▶ Run started: run_xyz789 ├─ [10:30:01] Researcher agent starting task... ├─ [10:30:05] Tool: SerperDevTool("quantum computing breakthroughs 2024") ├─ [10:30:12] Tool: SerperDevTool("quantum computing companies 2024") ├─ [10:30:25] Researcher agent completed task ├─ [10:30:26] Writer agent starting task... ├─ [10:30:58] Writer agent completed task ├─ [10:30:59] Artifact: report.md (3.2 KB) ✅ Run completed in 58.4s ``` ## Step 11: Get the Artifact ```bash theme={null} # List artifacts crewship runs artifacts run_xyz789 # Download the report crewship runs download run_xyz789 report.md ``` ## Next Steps Add real-time event handling Work with run outputs Build an agent with LangGraph (Python) Build an agent with LangGraph.js # Your First LangGraph Agent Source: https://docs.crewship.dev/guides/your-first-langgraph Build and deploy a LangGraph agent from scratch ## What We'll Build A research agent using LangGraph (Python) that: 1. Receives a topic as input 2. Runs a researcher node to gather key facts 3. Runs a reporter node to expand findings into a markdown report ## Prerequisites * Python 3.11+ * LangGraph installed (`pip install langgraph langchain-openai`) * Crewship CLI installed and authenticated Want to skip the setup? Clone the [langgraph-quickstart](https://github.com/Crewship/langgraph-quickstart) repo and run `crewship deploy` to get a working agent deployed in minutes. ## Step 1: Create the Project ```bash theme={null} mkdir research-agent && cd research-agent mkdir -p src/research_agent touch src/research_agent/__init__.py ``` Your project structure: ``` research-agent/ ├── src/ │ └── research_agent/ │ ├── __init__.py │ └── graph.py ├── langgraph.json ├── pyproject.toml └── crewship.toml ``` ## Step 2: Define Your Graph Create `src/research_agent/graph.py`: ```python graph.py theme={null} from typing import TypedDict from langchain_core.messages import SystemMessage from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph class State(TypedDict): topic: str research: str report: str llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.7) def researcher(state: State) -> dict: """Research a topic and produce bullet-point notes.""" response = llm.invoke([ SystemMessage(content=( "You are a senior researcher. Given a topic, produce 10 concise bullet " "points covering the most important facts, recent developments, and key " "insights. Return only the bullet list." )), SystemMessage(content=f"Topic: {state['topic']}"), ]) return {"research": response.content} def reporter(state: State) -> dict: """Expand research notes into a polished markdown report.""" response = llm.invoke([ SystemMessage(content=( "You are a senior reporting analyst. Given research bullet points, " "expand them into a well-structured markdown report with an introduction, " "detailed sections, and a conclusion." )), SystemMessage(content=f"Research notes:\n{state['research']}"), ]) return {"report": response.content} builder = StateGraph(State) builder.add_node("researcher", researcher) builder.add_node("reporter", reporter) builder.set_entry_point("researcher") builder.add_edge("researcher", "reporter") builder.set_finish_point("reporter") graph = builder.compile() ``` The compiled `graph` object is what Crewship invokes. Your input (e.g., `{"topic": "quantum computing"}`) becomes the initial state. ## Step 3: Add langgraph.json Create `langgraph.json` in the project root — this lets `crewship init` auto-detect the framework: ```json langgraph.json theme={null} { "graphs": { "agent": "./src/research_agent/graph.py:graph" } } ``` ## Step 4: Add Dependencies Create `pyproject.toml`: ```toml pyproject.toml theme={null} [project] name = "research-agent" version = "0.1.0" requires-python = ">=3.11" dependencies = [ "langgraph>=0.2.0", "langchain-openai>=0.2.0", ] ``` ## Step 5: Add Crewship Configuration Run `crewship init` to auto-generate the config — or create it manually: ```toml crewship.toml theme={null} [deployment] framework = "langgraph" entrypoint = "src.research_agent.graph:graph" python = "3.11" [build] exclude = ["tests"] [runtime] timeout = 300 memory = 512 ``` The entrypoint uses Python module path format: dots for directories, colon before the variable name. ## Step 6: Set Environment Variables ```bash theme={null} crewship env set OPENAI_API_KEY=sk-proj-... ``` ## Step 7: Deploy ```bash theme={null} crewship deploy ``` ``` 📦 Packaging agent... ☁️ Uploading build context... 🔨 Building image... ✅ Deployed successfully! Deployment: dep_abc123xyz Project: research-agent ``` ## Step 8: Run Your Agent ```bash theme={null} crewship invoke --input '{"topic": "quantum computing"}' --stream ``` Watch the execution: ``` ▶ Run started: run_xyz789 ├─ [10:30:01] Starting graph execution ├─ [10:30:02] Node: researcher starting... ├─ [10:30:12] Node: researcher completed ├─ [10:30:13] Node: reporter starting... ├─ [10:30:45] Node: reporter completed ✅ Run completed in 44.8s ``` ## Step 9: Access the Output The run result is the final graph state — a dictionary with all state keys: ```bash theme={null} # Get the run result curl https://api.crewship.dev/v1/runs/run_xyz789 \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json theme={null} { "status": "succeeded", "result": { "topic": "quantum computing", "research": "• Quantum computers use qubits...", "report": "# Quantum Computing\n\n## Introduction\n..." } } ``` To save the report as an artifact, write it to the `artifacts/` directory inside your node: ```python theme={null} def reporter(state: State) -> dict: response = llm.invoke([...]) with open("artifacts/report.md", "w") as f: f.write(response.content) return {"report": response.content} ``` ## Next Steps Real-time event streaming from runs Stateful conversations with LangGraph Build the same agent in TypeScript crewship.toml options # Your First LangGraph.js Agent Source: https://docs.crewship.dev/guides/your-first-langgraph-js Build and deploy a LangGraph.js agent in TypeScript from scratch ## What We'll Build A research agent using LangGraph.js (TypeScript) that: 1. Receives a topic as input 2. Runs a researcher node to gather key facts 3. Runs a reporter node to expand findings into a markdown report ## Prerequisites * Node.js 20+ * Crewship CLI installed and authenticated Want to skip the setup? Clone the [langgraph-js-quickstart](https://github.com/Crewship/langgraph-js-quickstart) repo and run `crewship deploy` to get a working agent deployed in minutes. ## Step 1: Create the Project ```bash theme={null} mkdir research-agent-js && cd research-agent-js mkdir src ``` Your project structure: ``` research-agent-js/ ├── src/ │ └── graph.ts ├── langgraph.json ├── package.json ├── tsconfig.json └── crewship.toml ``` ## Step 2: Define Your Graph Create `src/graph.ts`: ```typescript graph.ts theme={null} import { ChatOpenAI } from '@langchain/openai' import { StateGraph, Annotation } from '@langchain/langgraph' const State = Annotation.Root({ topic: Annotation(), research: Annotation(), report: Annotation(), }) const llm = new ChatOpenAI({ model: 'gpt-4o-mini', temperature: 0.7 }) async function researcher(state: typeof State.State) { const response = await llm.invoke([ { role: 'system', content: 'You are a senior researcher. Given a topic, produce 10 concise bullet ' + 'points covering the most important facts, recent developments, and key ' + 'insights. Return only the bullet list.', }, { role: 'user', content: `Topic: ${state.topic}` }, ]) return { research: typeof response.content === 'string' ? response.content : String(response.content) } } async function reporter(state: typeof State.State) { const response = await llm.invoke([ { role: 'system', content: 'You are a senior reporting analyst. Given research bullet points, ' + 'expand them into a well-structured markdown report with an introduction, ' + 'detailed sections, and a conclusion.', }, { role: 'user', content: `Research notes:\n${state.research}` }, ]) return { report: typeof response.content === 'string' ? response.content : String(response.content) } } const builder = new StateGraph(State) .addNode('researcher', researcher) .addNode('reporter', reporter) .addEdge('__start__', 'researcher') .addEdge('researcher', 'reporter') .addEdge('reporter', '__end__') export const graph = builder.compile() ``` The exported `graph` is what Crewship invokes. Your input (e.g., `{"topic": "quantum computing"}`) becomes the initial state. ## Step 3: Add langgraph.json Create `langgraph.json` in the project root — this lets `crewship init` auto-detect the framework: ```json langgraph.json theme={null} { "node_version": "20", "graphs": { "agent": "./src/graph.ts:graph" } } ``` ## Step 4: Add Dependencies Create `package.json`: ```json package.json theme={null} { "name": "research-agent-js", "version": "1.0.0", "type": "module", "dependencies": { "@langchain/langgraph": "^0.2.0", "@langchain/openai": "^0.3.0" } } ``` Create `tsconfig.json`: ```json tsconfig.json theme={null} { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "esModuleInterop": true } } ``` ## Step 5: Add Crewship Configuration Run `crewship init` to auto-generate the config — or create it manually: ```toml crewship.toml theme={null} [deployment] framework = "langgraph-js" entrypoint = "./src/graph.ts:graph" profile = "slim" [build] exclude = ["tests"] [runtime] timeout = 300 memory = 512 ``` LangGraph.js uses a file path entrypoint (with `./`), unlike Python frameworks which use a module path. The `python` field is not applicable. ## Step 6: Set Environment Variables ```bash theme={null} crewship env set OPENAI_API_KEY=sk-proj-... ``` ## Step 7: Deploy ```bash theme={null} crewship deploy ``` ``` 📦 Packaging agent... ☁️ Uploading build context... 🔨 Building image... ✅ Deployed successfully! Deployment: dep_abc123xyz Project: research-agent-js ``` ## Step 8: Run Your Agent ```bash theme={null} crewship invoke --input '{"topic": "quantum computing"}' --stream ``` Watch the execution: ``` ▶ Run started: run_xyz789 ├─ [10:30:01] Starting graph execution ├─ [10:30:02] Node: researcher starting... ├─ [10:30:12] Node: researcher completed ├─ [10:30:13] Node: reporter starting... ├─ [10:30:45] Node: reporter completed ✅ Run completed in 44.8s ``` ## Step 9: Access the Output The run result is the final graph state — an object with all state keys: ```bash theme={null} curl https://api.crewship.dev/v1/runs/run_xyz789 \ -H "Authorization: Bearer YOUR_API_KEY" ``` ```json theme={null} { "status": "succeeded", "result": { "topic": "quantum computing", "research": "• Quantum computers use qubits...", "report": "# Quantum Computing\n\n## Introduction\n..." } } ``` To save the report as an artifact, write it to the `artifacts/` directory inside your node: ```typescript theme={null} import { writeFileSync, mkdirSync } from 'fs' async function reporter(state: typeof State.State) { const response = await llm.invoke([...]) const content = String(response.content) mkdirSync('artifacts', { recursive: true }) writeFileSync('artifacts/report.md', content) return { report: content } } ``` ## Next Steps Real-time event streaming from runs Stateful conversations with LangGraph Build the same agent in Python crewship.toml options # Introduction Source: https://docs.crewship.dev/introduction Deploy AI agents, crews, and workflows in seconds. ## What is Crewship? Crewship is a **developer-first platform** for deploying and running AI agent workflows. It supports [CrewAI](https://docs.crewai.com), [LangGraph](https://langchain-ai.github.io/langgraph/) (Python), and [LangGraph.js](https://langchain-ai.github.io/langgraphjs/) out of the box, with a consistent deployment and invocation experience across all frameworks. Deploy your first agent in under 5 minutes with a single command Sensible defaults with optional configuration for advanced use cases Stream agent events and logs in real-time via SSE Automatic handling and storage of run outputs and generated files ## Supported Frameworks | Framework | Language | Framework ID | | ----------------------------------------------------------- | ----------------------- | -------------- | | [CrewAI](https://docs.crewai.com) | Python | `crewai` | | [LangGraph](https://langchain-ai.github.io/langgraph/) | Python | `langgraph` | | [LangGraph.js](https://langchain-ai.github.io/langgraphjs/) | TypeScript / JavaScript | `langgraph-js` | ## How It Works Crewship abstracts away infrastructure complexity so you can focus on building great AI agents: Build your agent locally using your framework of choice — CrewAI, LangGraph, or LangGraph.js Run `crewship deploy` to build, package, and deploy your agent to the cloud Trigger runs via CLI, API, or Console with real-time event streaming ## Next Steps Deploy your first crew in 5 minutes Learn about deployments, runs, and artifacts # Quickstart Source: https://docs.crewship.dev/quickstart Deploy your first AI agent in under 5 minutes ## Prerequisites Before you begin, make sure you have: * A **Crewship account** ([sign up here](https://console.crewship.dev)) * An agent project ready to deploy — CrewAI, LangGraph, or LangGraph.js Don't have a project yet? Clone one of our quickstart repos and deploy it in minutes: * [langgraph-quickstart](https://github.com/Crewship/langgraph-quickstart) — LangGraph (Python) * [langgraph-js-quickstart](https://github.com/Crewship/langgraph-js-quickstart) — LangGraph.js (TypeScript) * [crewai-quickstart](https://github.com/Crewship/crewai-quickstart) — CrewAI (Python) ## Install the CLI ```bash theme={null} curl -fsSL https://www.crewship.dev/install.sh | bash ``` ```powershell theme={null} Invoke-WebRequest -Uri "https://api.crewship.dev/cli/releases/latest/download?platform=windows-x64" -OutFile "$env:LOCALAPPDATA\Programs\crewship.exe" [Environment]::SetEnvironmentVariable("Path", "$([Environment]::GetEnvironmentVariable('Path', 'User'));$env:LOCALAPPDATA\Programs", "User") ``` Restart your terminal after running these commands. ## Authenticate Login to connect the CLI to your Crewship account: ```bash theme={null} crewship login ``` This opens a browser window to authenticate. Once complete, your credentials are stored locally. Run `crewship whoami` to verify your authentication status. ## Add Crewship Configuration Crewship currently supports CrewAI, LangGraph, and LangGraph.js. If you already have a project in one of these frameworks, you can deploy it on Crewship. If you want to deploy an agent built with a framework that we don't (yet) support, please send us a message at [mail@crewship.dev](mailto:mail@crewship.dev) so we can prioritize it! Initialize a `crewship.toml` file in your project: ```bash theme={null} crewship init ``` This auto-detects your framework and entrypoint: ``` 🔍 Initializing Crewship project in /path/to/my_crew Found pyproject.toml, reading project info... Detected CrewAI project Detected entrypoint: my_crew.crew:MyCrew ✅ Created crewship.toml ``` ``` 🔍 Initializing Crewship project in /path/to/my_agent Found langgraph.json, reading project info... Detected LangGraph project Detected entrypoint: src.my_agent.graph:graph ✅ Created crewship.toml ``` ``` 🔍 Initializing Crewship project in /path/to/my_agent Found langgraph.json, reading project info... Detected LangGraph.js project Detected entrypoint: ./src/graph.ts:graph ✅ Created crewship.toml ``` The `init` command automatically finds your entrypoint. You can also create `crewship.toml` manually — see the [configuration reference](/configuration/crewship-toml). ## Deploy Deploy your crew with a single command: ```bash theme={null} crewship deploy ``` You'll see output like: ``` 📦 Packaging crew... ☁️ Uploading build context... 🔨 Building image... ✅ Deployed successfully! Deployment: dep_abc123xyz Production URL: https://my-crew.crewship.run ``` You can also simply `run crewship deploy` in a new project, and it will log you in and initialize the project configuration automatically. ## Invoke Your Agent Run your deployed agent: ```bash CLI theme={null} crewship invoke --input '{"topic": "AI agents"}' ``` ```bash cURL theme={null} curl -X POST https://api.crewship.dev/v1/runs \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "deployment": "my-crew", "input": {"topic": "AI agents"} }' ``` ## Stream Events Watch your agent execute in real-time: ```bash theme={null} crewship invoke --input '{"topic": "AI agents"}' --stream ``` Events stream as they happen: ``` ▶ Run started: run_xyz789 ├─ [10:30:01] Starting execution ├─ [10:30:02] Agent: Researcher starting task... ├─ [10:30:25] Agent: Researcher completed task ├─ [10:30:26] Agent: Writer starting task... ├─ [10:30:58] Agent: Writer completed task ├─ [10:30:59] Artifact: report.md (2.4 KB) ✅ Run completed in 58.4s ``` ## View in Console Open the [Crewship Console](https://console.crewship.dev) to: * View run history and logs * Download artifacts * Manage environment variables * Monitor usage and costs ## Next Steps Understand deployments, runs, and artifacts Explore all CLI commands Configure secrets and API keys Real-time event streaming in depth