Skip to content
Packages Examples Agents Blog Get started

Your First App

Terminal window
uv add oridecon-cli
# or: pip install oridecon-cli
oridecon --version

Terminal window
oridecon new project hello --template web-api
cd hello

Templates (minimal, api, web-api, graphql, worker, full) change which packages and application.yaml sections you get. They do not change the tree. There is no --structure flag.

What landed is the same shape Project Structure describes: src/hello/app.py as the composition root, empty modules/, shared/ for cross-cutting, di/ for app providers when you generate them.


Terminal window
oridecon run

oridecon run auto-detects hello.app:app from [tool.oridecon] module and serves with reload on. Open:

You should see the generated OpenAPI. That is the “it works” check.

oridecon dev is the same idea with ORI_ENV=development. Do not reach for uvicorn … --factory unless you are deploying — see Deployment.


Terminal window
oridecon gen controller hello

That writes an unscoped controller at src/hello/controllers/hello_controller.py. Edit it:

src/hello/controllers/hello_controller.py
from oridecon.web import Controller, get
class HelloController(Controller):
prefix = "/api"
@get("/hello")
async def hello(self) -> dict:
return {"message": "Hello, Oridecon!"}
@get("/hello/{name}")
async def hello_name(self, name: str) -> dict:
return {"message": f"Hello, {name}!"}

The composition root discovers controllers. You do not list this class in app.py. Reload, then open http://127.0.0.1:8000/api/hello:

{"message": "Hello, Oridecon!"}

create_app() lists the modules this app uses. A hello API needs WebModule — controllers are discovered, not listed by hand.

src/hello/app.py
from oridecon import Application, OrideconConfig
from oridecon.web import WebModule
def create_app(config: OrideconConfig | None = None) -> Application:
application = Application(name="hello", config=config)
application.add_modules(
[
WebModule.configure(
discover=[
"hello.controllers",
"hello.modules",
]
),
]
)
return application
app = create_app()

When you add SQL or an agent, pass DatabaseModule.configure(...) or AgentsModule.configure(...) in the same list — that is how examples/sql-repository and examples/support-agent boot. App-root providers go through application.add_providers([...]).


Terminal window
oridecon gen service greetings

That lands in src/hello/services/. Type-hint it on the controller — the container injects it:

src/hello/services/greeting_service.py
from oridecon import singleton
@singleton
class GreetingService:
def greet(self, name: str) -> str:
return f"Hello, {name}! Welcome to Oridecon."
src/hello/controllers/hello_controller.py
from oridecon.web import Controller, get
from hello.services.greeting_service import GreetingService
class HelloController(Controller):
prefix = "/api"
def __init__(self, greeting: GreetingService) -> None:
self.greeting = greeting
@get("/hello/{name}")
async def hello_name(self, name: str) -> dict:
return {"message": self.greeting.greet(name)}

For config, lifecycle, or binding a protocol to an implementation, generate a provider into src/hello/di/ instead of using @singleton. See Core Concepts.


hello/
├── application.yaml
├── pyproject.toml
└── src/
└── hello/
├── app.py # create_app() — composition root
├── controllers/
│ └── hello_controller.py
├── services/
│ └── greeting_service.py
├── di/ # app providers, when you generate them
├── domains/ # appear when generated
├── infrastructure/
├── shared/
└── modules/
└── __init__.py # empty until oridecon new module

oridecon new module grows a bounded context in place. Nothing here has to be rewritten.