{"slug": "model-your-business-once-for-humans-and-ai-alike", "title": "Model your business once – for humans and AI alike", "summary": "Nexusx, a new Python package, lets developers model business entities, relationships, and use cases once, then derives GraphQL, REST, MCP, CLI, and TypeScript SDK interfaces from that single typed model, aiming to reduce maintenance costs and make AI agents first-class consumers. The package uses SQLModel entities and typed DTOs, with MCP as a native protocol and GraphQL under the hood, and includes Voyager for live entity-relationship visualization. It is installable via `pip install nexusx`.", "body_md": "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.\n\n`pip install nexusx`\n\nThe same typed business model serves AI agents and developers as first-class consumers.\n\nMCP is a native protocol: strongly typed, GraphQL under the hood.\n\nWrite SQLModel entities and typed DTOs; that is the whole job.\n\nLLMs 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.\n\nnexusx 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.\n\nAI writes the model and use-case methods — not scattered glue code. Small diffs, reviewable by humans.\n\nChange a business rule once; every protocol updates in sync. Maintenance cost does not multiply per delivery.\n\nTyped 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)\n\nSemantic-level isomorphism — every protocol is generated from the same typed model, not wrapped around a copy of it.\n\n```\n# \"list sprints\" — written once per protocol\n\n@app.get(\"/sprints\")\nasync def rest_list_sprints() -> list[SprintOut]:\n    ...  # query + assembly, again\n\n@strawberry.field\nasync def graphql_sprints(self) -> list[SprintType]:\n    ...  # types + loaders, again\n\n@mcp.tool()\nasync def sprints_for_agents() -> str:\n    ...  # JSON dumping, again\n\n# ↑ change the rule → fix every copy\nclass SprintService(UseCaseService):\n    \"\"\"Sprint planning operations.\"\"\"\n\n    @query\n    async def list_sprints(cls) -> list[SprintSummary]:\n        \"\"\"List sprints with tasks, owners, and task count.\"\"\"\n        return await load_sprints()\n\n# six deliveries, one model ↓\n```\n\nTyped FastAPI route, visible in OpenAPI.\n\n`create_use_case_router(api)`\n\nEntities become by_id / by_filter roots for exploring connected data.\n\n`Sprint { by_filter(limit: 10) { ... } }`\n\nUse-case methods become typed fields via the compose schema.\n\n`compose_query(app, query, args)`\n\nAgents discover it progressively.\n\n`create_use_case_graphql_mcp_server([api])`\n\nServices become command groups.\n\n`list_sprints --select \"name task_count\"`\n\nTyped client generated from the compose schema.\n\n`sprintService.listSprints()`\n\nTwo GraphQL surfaces for two different jobs — use either one, or both.\n\nSQLModel 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.\n\nGraphQLHandlerTyped business methods expose stable capabilities to web clients, integrations, and AI agents — served over REST, MCP, CLI, and SDK from one definition.\n\nUseCaseServiceEntities are not API contracts. DefineSubset hides internal columns, auto-loads relationships, and computes derived fields.\n\n``` python\n# Per-endpoint: manual SQL, N+1, dict munging\nasync def get_sprints():\n    sprints = await session.exec(select(Sprint))\n    result = []\n    for s in sprints:\n        tasks = await session.exec(\n            select(Task).where(Task.sprint_id == s.id))\n        for t in tasks:\n            t.owner = await session.get(User, t.owner_id)\n\n# N+1 queries, fragile dict construction\npython\nfrom nexusx import DefineSubset, ErManager, build_dto_select\n\nclass UserDTO(DefineSubset):\n    __subset__ = (User, (\"id\", \"name\"))\n\nclass TaskDTO(DefineSubset):\n    __subset__ = (Task, (\"id\", \"title\", \"owner_id\"))\n    owner: UserDTO | None = None   # auto-loaded\n\nclass SprintDTO(DefineSubset):\n    __subset__ = (Sprint, (\"id\", \"name\"))\n    tasks: list[TaskDTO] = []      # auto-loaded\n\ner = ErManager(entities=[User, Sprint, Task], session_factory=async_session)\nResolver = er.create_resolver()\n\nasync def load_sprints() -> list[SprintDTO]:\n    stmt = build_dto_select(SprintDTO)          # root columns only\n    async with async_session() as session:\n        rows = (await session.exec(stmt)).all()\n    dtos = [SprintDTO(**dict(r._mapping)) for r in rows]\n    return await Resolver().resolve(dtos)       # tree filled, batched\n\n# 1 query per relationship, zero N+1\n```\n\nThe same relationship model stretches into more advanced architectures.\n\nDataLoader batching, SQL column pruning, window-function pagination — and total_count computed only when the response asks for it.\n\npost_* for aggregations, ExposeAs / SendTo for cross-layer data flow.\n\nOrdinary Pydantic models as non-table graph roots — Redis, search, and SDK-backed data join the same graph.\n\nCompose multiple nexusx data graphs without a central gateway — homogeneous federation of nexusx services.\n\nComposedErManager composes multiple engines in one process; DTO federation loads public DTO trees across services.\n\nIndependently packaged applications and databases, combined into a single MCP server.\n\nThe principles that shape every API decision.\n\nOne 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.\n\nRedis, 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.\n\nBusiness 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.\n\nInstall 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.\n\n`npx skills add KLR-Pattern/nexusx -s nexusx-4phase -a claude-code`\n\nConfirm the domain model and persistence strategy with you before any code is written.\n\nEntities and relationships, GraphQL helper surface, then UseCase REST / MCP / CLI deliveries.\n\nOptionally emit a typed TypeScript SDK from the compose schema.\n\nWorks with your existing frameworks and tools.\n\nDeclare the model once — the data graph, response DTOs, and every delivery follow.", "url": "https://wpnews.pro/news/model-your-business-once-for-humans-and-ai-alike", "canonical_source": "https://klr-pattern.github.io/nexusx/", "published_at": "2026-08-15 14:08:40+00:00", "updated_at": "2026-08-15 14:41:37.254092+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "artificial-intelligence"], "entities": ["nexusx", "GraphQL", "REST", "MCP", "CLI", "TypeScript SDK", "SQLModel", "Voyager"], "alternates": {"html": "https://wpnews.pro/news/model-your-business-once-for-humans-and-ai-alike", "markdown": "https://wpnews.pro/news/model-your-business-once-for-humans-and-ai-alike.md", "text": "https://wpnews.pro/news/model-your-business-once-for-humans-and-ai-alike.txt", "jsonld": "https://wpnews.pro/news/model-your-business-once-for-humans-and-ai-alike.jsonld"}}