Build and deploy your own tools.
The Grid is open for extension. If you need something that doesn't exist, create it.
→ Extend overview — developer path and related guides
Overview
Apps are Python scripts with:
- Typed inputs — What the app accepts
- Typed outputs — What it returns
- Lifecycle methods — Setup, run, cleanup
The CLI helps you create, test, and deploy.
Quick Start
Install the CLI
1curl -fsSL https://cli.inference.sh | shLogin
1belt loginCreate an App
1mkdir my-app && cd my-app2belt initAnswer the prompts:
- Name:
my-app - Description: "What my app does"
- Category: image, text, audio, etc.
- Python version: 3.10, 3.11, or 3.12
- GPU required: Yes or No
This creates:
1my-app/2├── inf.yml # Configuration3├── inference.py # Your code4├── requirements.txt # Dependencies5└── ...The App Template
inference.py
1from inferencesh import BaseApp, BaseAppInput, BaseAppOutput, File2from pydantic import Field3from typing import Optional45class AppInput(BaseAppInput):6 prompt: str = Field(description="What to generate")7 style: str = Field(default="default", description="Output style")89class AppOutput(BaseAppOutput):10 result: str = Field(description="Generated text")11 image: Optional[File] = Field(default=None, description="Generated image")1213class App(BaseApp):14 async def setup(self, metadata):15 """Called once when the worker starts.16 Load models, initialize resources here."""17 # self.model = load_your_model()18 pass19 20 async def run(self, input_data: AppInput, metadata) -> AppOutput:21 """Called for each request.22 Process input and return output."""23 24 # Access inputs25 prompt = input_data.prompt26 style = input_data.style27 28 # Log progress (visible in real-time)29 metadata.log("Processing...")30 31 # Do your work32 result = f"Generated: {prompt} in {style} style"33 34 # Return output35 return AppOutput(result=result)36 37 async def unload(self):38 """Called on shutdown. Cleanup resources."""39 passInput/Output Types
| Type | Example | Description |
|---|---|---|
str | "hello" | Text |
int | 42 | Integer |
float | 3.14 | Decimal |
bool | true | Boolean |
List[T] | [1, 2, 3] | Array |
Optional[T] | null or value | Nullable |
File | {"uri": "..."} | File reference |
Working with Files
Input files are downloaded automatically:
1async def run(self, input_data: AppInput, metadata) -> AppOutput:2 # File is ready to use3 image_path = input_data.image.path4 5 with open(image_path, "rb") as f:6 data = f.read()Output files are uploaded automatically:
1async def run(self, input_data: AppInput, metadata) -> AppOutput:2 # Write to a file3 output_path = "/tmp/result.png"4 save_image(output_path)5 6 # Return it7 return AppOutput(image=File(path=output_path))Configuration
inf.yml
1namespace: myteam2name: my-app3title: My App4description: What my app does5category: image6kernel: python-3.1178resources:9 gpu:10 count: 111 vram: 8000 # MB12 type: nvidia13 ram: 16000 # MBSetup Parameters
Use an AppSetup class to define configuration that is fixed while the app is loaded, such as which model to load. Setup parameters replaced app variants.
See Setup Parameters.
Dependencies
requirements.txt — Python packages:
1torch>=2.0.02transformers>=4.30.03accelerate4huggingface_hub5pillow>=9.0.0List every package your code imports. The Python base environment includes only build tools, pydantic and inferencesh. See Python environment.
packages.txt — System packages (apt):
1ffmpeg2libgl1-mesa-glxRequirements
If your app needs external API keys or OAuth credentials, declare them:
1# inf.yml2secrets:3 - key: OPENAI_API_KEY4 description: For GPT-4 API calls56 - key: REPLICATE_API_TOKEN7 description: For model inference8 optional: true910credentials:11 - key: google.sheets12 description: Read/write spreadsheets1314 - key: x.tweet.write15 description: Post tweets16 optional: trueRequired items must be configured before the app runs.
Optional items won't block execution if missing.
→ Learn more about Secrets & Credentials
Multi-Function Apps
By default, apps expose a single run method. You can define multiple functions to handle different operations in one app:
1from inferencesh import BaseApp, BaseAppInput, BaseAppOutput, File2from pydantic import Field34class UpscaleInput(BaseAppInput):5 image: File = Field(description="Image to upscale")6 scale: int = Field(default=2, description="Scale factor")78class UpscaleOutput(BaseAppOutput):9 image: File = Field(description="Upscaled image")1011class RemoveBgInput(BaseAppInput):12 image: File = Field(description="Image to process")1314class RemoveBgOutput(BaseAppOutput):15 image: File = Field(description="Image with background removed")1617class App(BaseApp):18 async def setup(self, metadata):19 # Load models for all functions20 pass2122 async def upscale(self, input_data: UpscaleInput, metadata) -> UpscaleOutput:23 # Upscale logic24 ...2526 async def remove_bg(self, input_data: RemoveBgInput, metadata) -> RemoveBgOutput:27 # Background removal logic28 ...Each public method (other than setup/unload) becomes a callable function with its own input/output schema.
Testing Multi-Function Apps
1# Test a specific function2belt app test --function upscale --input upscale_input.json34# Test another function5belt app test --function remove_bg --input removebg_input.jsonRunning Multi-Function Apps in the Cloud
1belt app run user/image-tools --function upscale --input input.jsonWhen used as an agent tool, each function appears as a separate tool the agent can call.
Deploy
1belt app deployThe CLI:
- Validates your app
- Installs dependencies locally
- Tests the structure
- Packages everything
- Uploads to inference shell
Output:
1┌──────────────────────────────────────┐2│ deployment summary │3├──────────────────────────────────────┤4│ │5│ final status: success │6│ duration: 45s │7│ user: yourname │8│ app: my-app │9│ link: https://app.inference.sh/... │10│ │11└──────────────────────────────────────┘Testing Locally
Generate Example Input
1belt app test --save-example2# Creates input.jsonRun Locally
1belt app test --input input.json23# Multi-function apps: specify which function to call4belt app test --function upscale --input input.jsonDebug Mode
1belt app test --input input.json --debugAI-Friendly Development
The CLI creates a CLAUDE.md file with instructions for AI assistants. This means you can:
- Describe what you want to an AI (ChatGPT, Claude, etc.)
- Share your app structure
- Get working code
- Deploy with
belt app deploy
The template and structure are designed for AI code generation.
Editing in the Workspace
After deploying, edit settings in the web interface:
- Setup Parameters — Configure initialization defaults
- Images — Card, thumbnail, banner
- Description — Help others find your app
- Visibility — Public or private
- Lifecycle status — Whether the app accepts new runs (
active,maintenance,deprecated, orretired)
Set lifecycle status and an optional status message in the Visibility section on your app's detail page. Visitors see a banner when status is not active. maintenance and retired block new runs; deprecated still runs but signals that callers should migrate.
→ Apps API — App lifecycle status
These changes don't require the CLI.
Best Practices
Keep Apps Focused
1❌ Don't: One app that does everything2✓ Do: Single-purpose apps that compose wellDownload Models in Setup
1async def setup(self, metadata):2 # Good: Download on first run, cached afterward3 # (huggingface_hub must be in requirements.txt)4 from huggingface_hub import hf_hub_download5 self.model_path = hf_hub_download("model-name", "model.bin")Don't bundle large models — they're cached after first download.
Log Progress
1async def run(self, input_data: AppInput, metadata) -> AppOutput:2 metadata.log("Step 1: Loading image...")3 # ...4 metadata.log("Step 2: Processing...")5 # ...6 metadata.log("Step 3: Saving result...")Users see these in real-time.
Handle Errors Gracefully
1async def run(self, input_data: AppInput, metadata) -> AppOutput:2 if not input_data.image.exists():3 raise ValueError("Image file not found")4 5 try:6 result = process(input_data)7 except ProcessingError as e:8 metadata.log(f"Error: {e}")9 raise RuntimeError(f"Processing failed: {e}")What's Next?
- Apps — See your app in the Grid
- Flows — Use your app in workflows
- Agents — Add your app as an agent tool
- Secrets & Credentials — Declare external requirements
- API & SDK — Run your app programmatically