# 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