# Model your business once – for humans and AI alike

> Source: <https://klr-pattern.github.io/nexusx/>
> Published: 2026-08-15 14:08:40+00:00

Model your business entities, relationships, and use cases once — GraphQL, REST, MCP, CLI, and TS SDK all derive from it. Data is a graph; tools are just its projections.

`pip install nexusx`

The same typed business model serves AI agents and developers as first-class consumers.

MCP is a native protocol: strongly typed, GraphQL under the hood.

Write SQLModel entities and typed DTOs; that is the whole job.

LLMs generate code fast — but without structural constraints, the debt surfaces weeks later: duplicated logic, components bleeding into each other, debugging by guesswork. The industry calls it the cost of vibe coding.

nexusx narrows what AI writes to a **declarative model** — entities, relationships, and typed use-case methods. Structure is not something the AI has to get right; it is guaranteed by the model.

AI writes the model and use-case methods — not scattered glue code. Small diffs, reviewable by humans.

Change a business rule once; every protocol updates in sync. Maintenance cost does not multiply per delivery.

Typed contracts, plus Voyager: entities, relationships, use cases, and their dependencies rendered as one live ER view — grasp the whole project without reading code first, whether you are a new human or a fresh AI session. [Voyager →](advanced/voyager)

Semantic-level isomorphism — every protocol is generated from the same typed model, not wrapped around a copy of it.

```
# "list sprints" — written once per protocol

@app.get("/sprints")
async def rest_list_sprints() -> list[SprintOut]:
    ...  # query + assembly, again

@strawberry.field
async def graphql_sprints(self) -> list[SprintType]:
    ...  # types + loaders, again

@mcp.tool()
async def sprints_for_agents() -> str:
    ...  # JSON dumping, again

# ↑ change the rule → fix every copy
class SprintService(UseCaseService):
    """Sprint planning operations."""

    @query
    async def list_sprints(cls) -> list[SprintSummary]:
        """List sprints with tasks, owners, and task count."""
        return await load_sprints()

# six deliveries, one model ↓
```

Typed FastAPI route, visible in OpenAPI.

`create_use_case_router(api)`

Entities become by_id / by_filter roots for exploring connected data.

`Sprint { by_filter(limit: 10) { ... } }`

Use-case methods become typed fields via the compose schema.

`compose_query(app, query, args)`

Agents discover it progressively.

`create_use_case_graphql_mcp_server([api])`

Services become command groups.

`list_sprints --select "name task_count"`

Typed client generated from the compose schema.

`sprintService.listSprints()`

Two GraphQL surfaces for two different jobs — use either one, or both.

SQLModel entities and relationships become by_id / by_filter query roots. No relationship resolvers to write — DataLoader batching keeps it N+1-proof as callers traverse.

GraphQLHandlerTyped business methods expose stable capabilities to web clients, integrations, and AI agents — served over REST, MCP, CLI, and SDK from one definition.

UseCaseServiceEntities are not API contracts. DefineSubset hides internal columns, auto-loads relationships, and computes derived fields.

``` python
# Per-endpoint: manual SQL, N+1, dict munging
async def get_sprints():
    sprints = await session.exec(select(Sprint))
    result = []
    for s in sprints:
        tasks = await session.exec(
            select(Task).where(Task.sprint_id == s.id))
        for t in tasks:
            t.owner = await session.get(User, t.owner_id)

# N+1 queries, fragile dict construction
python
from nexusx import DefineSubset, ErManager, build_dto_select

class UserDTO(DefineSubset):
    __subset__ = (User, ("id", "name"))

class TaskDTO(DefineSubset):
    __subset__ = (Task, ("id", "title", "owner_id"))
    owner: UserDTO | None = None   # auto-loaded

class SprintDTO(DefineSubset):
    __subset__ = (Sprint, ("id", "name"))
    tasks: list[TaskDTO] = []      # auto-loaded

er = ErManager(entities=[User, Sprint, Task], session_factory=async_session)
Resolver = er.create_resolver()

async def load_sprints() -> list[SprintDTO]:
    stmt = build_dto_select(SprintDTO)          # root columns only
    async with async_session() as session:
        rows = (await session.exec(stmt)).all()
    dtos = [SprintDTO(**dict(r._mapping)) for r in rows]
    return await Resolver().resolve(dtos)       # tree filled, batched

# 1 query per relationship, zero N+1
```

The same relationship model stretches into more advanced architectures.

DataLoader batching, SQL column pruning, window-function pagination — and total_count computed only when the response asks for it.

post_* for aggregations, ExposeAs / SendTo for cross-layer data flow.

Ordinary Pydantic models as non-table graph roots — Redis, search, and SDK-backed data join the same graph.

Compose multiple nexusx data graphs without a central gateway — homogeneous federation of nexusx services.

ComposedErManager composes multiple engines in one process; DTO federation loads public DTO trees across services.

Independently packaged applications and databases, combined into a single MCP server.

The principles that shape every API decision.

One field selection shapes the GraphQL response, the SQL columns loaded, the DTO fields copied, the MCP output, CLI --select, and whether total_count is even computed.

Redis, search engines, other databases, external APIs — declare a Relationship with an async batch function and they join the same loader, DTO, GraphQL, and ER-diagram infrastructure.

Business methods depend on no protocol object — builders inspect the typed signature and attach REST / MCP / CLI / SDK adapters. FromContext injects trusted values (user, tenant) without exposing them as client arguments.

Install the 4-phase skill into your coding agent — Claude Code, Codex, Cursor, and more — then describe your app in plain words. The agent drives the workflow; you review the model.

`npx skills add KLR-Pattern/nexusx -s nexusx-4phase -a claude-code`

Confirm the domain model and persistence strategy with you before any code is written.

Entities and relationships, GraphQL helper surface, then UseCase REST / MCP / CLI deliveries.

Optionally emit a typed TypeScript SDK from the compose schema.

Works with your existing frameworks and tools.

Declare the model once — the data graph, response DTOs, and every delivery follow.
