> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cycls.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy

> Publish a function, app or agent to a URL, set its size and limits, and understand what survives a redeploy.

This page is for developers taking a working local file to production.

**Prerequisites:** a `CYCLS_API_KEY` from [Cycls Cloud](https://cloud.cycls.com),
set in the environment or in a `.env` file beside your code.

```bash theme={null}
cycls deploy my_agent.py
#   [DONE] https://my-agent.cycls.ai
```

## Naming

The deployment name is the decorator's `name=` or the function name, and it
becomes the subdomain:

```python theme={null}
@cycls.agent(name="atlas", web=web, volumes={"/workspace": chats})
async def my_agent(context): ...
# https://atlas.cycls.ai
```

Redeploying the same name updates it in place. Names are checked for availability
before the archive uploads, and the error names the conflict.

To pick one target out of a file with several decorated objects:

```bash theme={null}
cycls deploy file.py::atlas
```

## What deploy produces

Deploy reads the shape of the decorated function:

| Shape                            | Result                                                 |
| -------------------------------- | ------------------------------------------------------ |
| `@cycls.agent`                   | a chat product at `https://<name>.cycls.ai`            |
| `@cycls.app`                     | an ASGI service at `https://<name>.cycls.ai`           |
| `@cycls.function` taking `port`  | a server at `https://<name>.cycls.ai`                  |
| `@cycls.function` with no `port` | a named endpoint, called with `cycls.remote("<name>")` |

## Sizing and limits

```python theme={null}
@cycls.function(
    image=image,
    cpu=4,
    memory="8Gi",
    timeout=1800,
    concurrency=1,
)
def train(epochs): ...
```

| Argument      | Accepted values      | Default         | Notes                                                      |
| ------------- | -------------------- | --------------- | ---------------------------------------------------------- |
| `cpu`         | 1, 2, 4, 6, 8        | platform choice | raised automatically if `memory` requires more             |
| `memory`      | `512Mi` to `32Gi`    | `1Gi`           |                                                            |
| `timeout`     | seconds, up to 3600  | 1200            | how long one request may run                               |
| `concurrency` | integer              | high            | requests one instance serves at once. Set to 1 for compute |
| `volumes`     | mount path to volume | none            | required at `/workspace` for agents                        |
| `schedule`    | `cycls.Cron(...)`    | none            | bare functions only                                        |

Instances scale to zero when idle, so an unused deployment costs nothing and the
next call pays a cold start of a few seconds.

## Environment variables

Values reach the container two ways.

1. Bundle a dotenv file with the image. The SDK loads `.env` automatically at
   import.

   ```python theme={null}
   image = cycls.Image().copy(".providers.env", ".env")
   ```

2. Read `os.environ` inside the function body for values the platform injects,
   such as `CYCLS_VOLUMES`.

Keep `CYCLS_API_KEY` out of the image. It is a deploy credential, not a runtime
one. See [Environment variables](/reference/environment) for the full list.

## Calling a deployed endpoint

```python theme={null}
import cycls

pi = cycls.remote("simulate")(10_000_000)
results = cycls.remote("simulate").map([10**6] * 100)
```

Authentication is a token derived as `sha256(api_key : name)`, computed
independently by the deployer and the caller and stored nowhere. Any machine
holding your `CYCLS_API_KEY` can call your deployments, and nothing else can.

Rotating the key strands existing services, because their baked token came from
the old key. Remove and redeploy them after a rotation.

Every call carries its Python and cloudpickle versions. The endpoint refuses a
pickle that cannot cross the boundary and returns an explicit error instead of a
confusing unpickle failure. Redeploy from the calling environment to resolve it.

## Isolation boundary

Deployments under one account share a trust domain. Code running in one can reach
another's workspace storage. For hard isolation, such as production against
experiments or separating clients, deploy from a separate organization. Each
organization is its own tenant with its own boundary.

## Removing a deployment

```bash theme={null}
cycls rm notes          # asks for confirmation
cycls rm notes -y       # skips it
```

`cycls rm` deletes the deployment and detaches its volumes. Volume data is not
touched, and redeploying the same name reattaches it with files intact. Deleting
data is always explicit:

```bash theme={null}
cycls volume delete notes-data
```

## Deploying from Python

```python theme={null}
my_agent.deploy()
my_app.deploy()
simulate.deploy()
```

Keep these out of module scope. Every command imports your file, so a top-level
`deploy()` fires during `cycls shell` and `cycls deploy` too.

```python theme={null}
if __name__ == "__main__":
    my_agent.deploy()
```

## Next

<Card title="Observability" icon="chart-line" href="/ship/observability">
  Logs, error references, cost and SQL over both.
</Card>
