Skip to content
Next-Gen Business Modeling · AI-Native · SQLModel

Model your business once —
for humans and AI alike.

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

AI-native integration — not bolted on

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

🤖

For AI — first-class

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

  • Context efficiency — agents select exactly the fields they need; one call returns a nested, N+1-proof tree with only what was asked.
  • Progressive disclosure — list_apps → describe_compose_schema → describe_compose_method → compose_query; the schema enters context piece by piece, never whole.
  • MCP & context efficiency →
🧑‍💻

For Human — same model

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

  • REST routes, GraphQL schema, CLI, and TS SDK — zero boilerplate.
  • Change business logic once — every protocol updates in sync.

Any model can ship an app. Almost none can keep it maintainable.

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.

✍️

A small, typed surface

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

📌

One source of truth

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

👁️

Understandable by construction

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 →

One model, six deliveries

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

Same operation, three copies
# "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
One UseCaseService method
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 ↓
🌐

REST + OpenAPI

Typed FastAPI route, visible in OpenAPI.

create_use_case_router(api)
🟣

GraphQL · data graph

Entities become by_id / by_filter roots for exploring connected data.

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

GraphQL · operation graph

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

compose_query(app, query, args)
🤖

MCP

Agents discover it progressively.

create_use_case_graphql_mcp_server([api])
⌨️

CLI

Services become command groups.

list_sprints --select "name task_count"
📘

TS SDK

Typed client generated from the compose schema.

sprintService.listSprints()

One model, two graphs

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

🧭

Data graph — explore and slice

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.

GraphQLHandler
⚙️

Operation graph — invoke capabilities

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

UseCaseService

Shape application responses

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

Manual query + assembly
# 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
Declarative DTO + auto-loading
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

Beyond one database

The same relationship model stretches into more advanced architectures.

Performance by construction

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

🔀

Derived Fields & Cross-Layer

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

🧲

Virtual Entities

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

🌐

Entity Federation

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

🧱

Composed & DTO Federation

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

🗃️

Multi-App MCP

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

Three ideas behind nexusx

The principles that shape every API decision.

🎯

Selection is first-class

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.

🌉

Relationships beyond the ORM

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.

📦

Delivery is layered on later

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.

Skip the API manual — build with an agent

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
🗺️

Phase 0 — model the domain

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

🏗️

Phase 1–3 — build the layers

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

🚀

Phase 4 — generate the SDK

Optionally emit a typed TypeScript SDK from the compose schema.

Built for your stack

Works with your existing frameworks and tools.

Start from entities, not boilerplate

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