Distribute Intelligence
Project description
Distribute Intelligence
Website | Docs | Tutorial
Cycls
The open-source SDK for distributing AI agents.
Agent extends App (prompts, skills)
└── App extends Function (web UI)
└── Function (containerization)
Distribute Intelligence
Write a function. Deploy it as an API, a web interface, or both. Add authentication, analytics, and monetization with flags.
import cycls
cycls.api_key = "YOUR_CYCLS_API_KEY"
@cycls.app(pip=["openai"])
async def app(context):
from openai import AsyncOpenAI
client = AsyncOpenAI()
stream = await client.responses.create(
model="o3-mini",
input=context.messages,
stream=True,
reasoning={"effort": "medium", "summary": "auto"},
)
async for event in stream:
if event.type == "response.reasoning_summary_text.delta":
yield {"type": "thinking", "thinking": event.delta} # Renders as thinking bubble
elif event.type == "response.output_text.delta":
yield event.delta
app.deploy() # Live at https://agent.cycls.ai
Installation
pip install cycls
Requires Docker. See the full tutorial for a comprehensive guide.
What You Get
- Streaming API - OpenAI-compatible
/chat/completionsendpoint - Web Interface - Chat UI served automatically
- Authentication -
auth=Trueenables JWT-based access control - Analytics -
analytics=Truetracks usage - Monetization -
plan="cycls_pass"integrates with Cycls Pass subscriptions - Native UI Components - Render thinking bubbles, tables, code blocks in responses
Running
app.local() # Development with hot-reload (localhost:8080)
app.local(watch=False) # Development without hot-reload
app.deploy() # Production: https://agent.cycls.ai
Get an API key at cycls.com.
Authentication & Analytics
See the tutorial for full auth and monetization examples.
@cycls.app(pip=["openai"], auth=True, analytics=True)
async def app(context):
# context.user available when auth=True
user = context.user # User(id, email, name, plans)
yield f"Hello {user.name}!"
| Flag | Description |
|---|---|
auth=True |
Universal user pool via Cycls Pass (Clerk-based). You can also use your own Clerk auth. |
analytics=True |
Rich usage metrics available on the Cycls dashboard. |
plan="cycls_pass" |
Monetization via Cycls Pass subscriptions. Enables both auth and analytics. |
Native UI Components
Yield structured objects for rich streaming responses. See the tutorial for all component types and examples.
@cycls.app()
async def demo(context):
yield {"type": "thinking", "thinking": "Analyzing the request..."}
yield "Here's what I found:\n\n"
yield {"type": "table", "headers": ["Name", "Status"]}
yield {"type": "table", "row": ["Server 1", "Online"]}
yield {"type": "table", "row": ["Server 2", "Offline"]}
yield {"type": "code", "code": "result = analyze(data)", "language": "python"}
yield {"type": "callout", "callout": "Analysis complete!", "style": "success"}
| Component | Streaming |
|---|---|
{"type": "thinking", "thinking": "..."} |
Yes |
{"type": "code", "code": "...", "language": "..."} |
Yes |
{"type": "table", "headers": [...]} |
Yes |
{"type": "table", "row": [...]} |
Yes |
{"type": "status", "status": "..."} |
Yes |
{"type": "callout", "callout": "...", "style": "..."} |
Yes |
{"type": "image", "src": "..."} |
Yes |
Thinking Bubbles
The {"type": "thinking", "thinking": "..."} component renders as a collapsible thinking bubble in the UI. Each yield appends to the same bubble until a different component type is yielded:
# Multiple yields build one thinking bubble
yield {"type": "thinking", "thinking": "Let me "}
yield {"type": "thinking", "thinking": "analyze this..."}
yield {"type": "thinking", "thinking": " Done thinking."}
# Then output the response
yield "Here's what I found..."
This works seamlessly with OpenAI's reasoning models - just map reasoning summaries to the thinking component.
Context Object
@cycls.app()
async def chat(context):
context.messages # [{"role": "user", "content": "..."}]
context.messages.raw # Full data including UI component parts
context.user # User(id, email, name, plans) when auth=True
API Endpoints
| Endpoint | Format |
|---|---|
POST chat/cycls |
Cycls streaming protocol |
POST chat/completions |
OpenAI-compatible |
Streaming Protocol
Cycls streams structured components over SSE:
data: {"type": "thinking", "thinking": "Let me "}
data: {"type": "thinking", "thinking": "analyze..."}
data: {"type": "text", "text": "Here's the answer"}
data: {"type": "callout", "callout": "Done!", "style": "success"}
data: [DONE]
See docs/streaming-protocol.md for frontend integration.
Declarative Infrastructure
Define your entire runtime in the decorator. See the tutorial for more details.
@cycls.app(
pip=["openai", "pandas", "numpy"],
apt=["ffmpeg", "libmagic1"],
copy=["./utils.py", "./models/", "/absolute/path/to/config.json"],
copy_public=["./assets/logo.png", "./static/"],
)
async def my_app(context):
...
pip - Python Packages
Install any packages from PyPI. These are installed during the container build.
pip=["openai", "pandas", "numpy", "transformers"]
apt - System Packages
Install system-level dependencies via apt-get. Need ffmpeg for audio processing? ImageMagick for images? Just declare it.
apt=["ffmpeg", "imagemagick", "libpq-dev"]
copy - Bundle Files and Directories
Include local files and directories in your container. Works with both relative and absolute paths. Copies files and entire directory trees.
copy=[
"./utils.py", # Single file, relative path
"./models/", # Entire directory
"/home/user/configs/app.json", # Absolute path
]
Then import them in your function:
@cycls.app(copy=["./utils.py"])
async def chat(context):
from utils import helper_function # Your bundled module
...
copy_public - Static Files
Files and directories served at the /public endpoint. Perfect for images, downloads, or any static assets your agent needs to reference.
copy_public=["./assets/logo.png", "./downloads/"]
Access them at https://your-app.cycls.ai/public/logo.png.
What You Get
- One file - Code, dependencies, configuration, and infrastructure together
- Instant deploys - Unchanged code deploys in seconds from cache
- No drift - What you see is what runs. Always.
- Just works - Closures, lambdas, dynamic imports - your function runs exactly as written
No YAML. No Dockerfiles. No infrastructure repo. The code is the deployment.
Learn More
- Tutorial - Comprehensive guide from basics to advanced
- Streaming Protocol - Frontend integration
- Runtime - Containerization details
- Examples - Working code samples
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cycls-0.0.2.110.tar.gz.
File metadata
- Download URL: cycls-0.0.2.110.tar.gz
- Upload date:
- Size: 918.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.25 {"installer":{"name":"uv","version":"0.9.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e85095c11553186d6e3ef09a416335f8131519d6058ff00fc586c183e2921351
|
|
| MD5 |
0f055dc483ebd352e95db6546996936c
|
|
| BLAKE2b-256 |
14a7cd5677574f3cbdc3cc749943441fdb972b485b755a08dd64fd02df592ad3
|
File details
Details for the file cycls-0.0.2.110-py3-none-any.whl.
File metadata
- Download URL: cycls-0.0.2.110-py3-none-any.whl
- Upload date:
- Size: 925.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.25 {"installer":{"name":"uv","version":"0.9.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e8631fdaba95cf45988bbf688e1ddbddb1707036fb2e8c404c5d2d0b859e379
|
|
| MD5 |
c5374189dc1370e41a99fd42837826ed
|
|
| BLAKE2b-256 |
b580c4037d6f1ef6014d2a04b68a388e3813fb7dbce914239570781de28c2cee
|