Imported from xDogBaby/Nexus (
backend/AGENTS.md). Install upstream withnpx skills add xDogBaby/Nexus --skill backend. Copyright stays with the author.
Backend Agent Instructions
This file defines the architecture rules for contributors and coding agents working under backend/.
Top-Level Shape
backend/
app/ backend application, DDD-style
api/ interface layer: receive requests and return responses
svc/ service layer: use-case orchestration and business workflows
domain/ domain layer: core models, rules, and state
infra/ infrastructure layer: database, external APIs, files, cache
harness/ reusable, business-neutral agent runtime framework
skills/ public/custom skills loaded by harness
shared/ cross-service schemas
openavatarchat/ digital-human dependency, currently unchanged
app and harness are siblings. openavatarchat is intentionally left unchanged unless the user explicitly asks for it.
Dependency Rules
Allowed dependency direction inside app:
api -> svc -> domain
api -> svc -> infra
svc -> domain
svc -> infra
infra -> domain
Allowed boundary between app and harness:
app -> harness
harness -> shared
Hard rule:
harness must never import app
That rule applies to production code and harness tests. If a test imports app, it belongs under backend/tests, not backend/harness/tests.
Platform capabilities, MCP classification, and role policy are owned by
app/infra/agent_runtime/profile.yaml. Harness reads that YAML as external
configuration data (or the path from NEXUS_RUNTIME_PROFILE_PATH); it must not
import an app module to obtain business policy.
App Layers
app/api
Interface layer. It owns FastAPI routes, request/response schemas, and protocol adapters such as MCP servers.
Allowed:
- Validate transport input.
- Call
app.svcuse cases. - Return HTTP/MCP-friendly responses.
Forbidden:
- Provider login flows.
- MongoDB write logic.
- Agent reasoning.
- Tool selection or agent-graph behavior.
- Knowledge-base parsing/indexing/retrieval internals.
app/svc
Service layer. It owns use-case orchestration and business workflows.
Allowed:
- Coordinate domain contracts.
- Use repositories, external provider clients, and other infra adapters.
- Build services used by
api. - Call
harnessthrough explicit clients when the backend app needs agent runtime behavior.
Forbidden:
- FastAPI route definitions.
- Low-level database driver code.
- Agent runtime internals.
app/domain
Domain layer. It owns core business concepts, contracts, rules, and state.
Use this layer for provider payload models, operation enums, validation rules, and business facts that should not depend on HTTP, MongoDB, MCP, or external SDKs.
app/infra
Infrastructure layer. It owns technical adapters:
- settings and constants
- MongoDB clients, schema bootstrap, migrations, repositories
- provider HTTP clients
- file/cache/vector-store adapters
- permissions
- logging/observability
- local implementation of external capabilities, such as
app/infra/knowledge_base - app-specific agent runtime profile files, such as
app/infra/agent_runtime/profile.yaml
Infra may depend on domain, but must not perform agent planning or tool routing.
Harness
backend/harness/ is the generic agent runtime. It owns:
- intent recognition
- lead-agent planning
- provider-native Tool Use graph execution
- permissions around tool execution
- tool registry and local tool plugins
- MCP client integration
- memory snapshots
- model clients
- response assembly
- skill discovery and progressive loading
Harness code must be reusable across multiple operation domains. It must not import app.
Framework-native Tool Use declarations belong in harness/tools/builtins/.
For example, request_human_input is a generic native tool contract there;
the graph's durable interrupt/resume mechanics remain in harness/runtime/.
Application-persistent operations, such as Scheduler management, belong behind
an app MCP server instead of a Harness local tool plugin.
Harness prompts must be task-neutral. They may describe runtime behavior, JSON output contracts, tool-use safety, context confidentiality, and skill-loading rules. They must not contain app-specific business examples, provider names, domain routes, role names, knowledge-base IDs, or product-specific workflow assumptions.
Business-specialized behavior belongs in one of these places:
- runtime profile YAML selected by
NEXUS_RUNTIME_PROFILE_PATH - skill files under
backend/skills/publicorbackend/skills/custom - backend app code under
backend/app - external HTTP or MCP services
If harness needs a backend capability, expose that capability over an external boundary such as HTTP or MCP, then call it as a remote service. Do not import app.svc, app.domain, or app.infra from harness.
Runtime Profile
Harness loads runtime metadata from YAML. The default app-owned profile is:
backend/app/infra/agent_runtime/profile.yaml
App-specific business configuration should live outside harness, for example:
backend/app/infra/agent_runtime/profile.yaml
Select an app profile with:
$env:NEXUS_RUNTIME_PROFILE_PATH = "C:\Users\HP\Documents\GitHub\Nexus\backend\app\infra\agent_runtime\profile.yaml"
The profile owns:
- non-tool intent routes
- model-visible tool descriptions, task domains, permissions, subagent bindings, and skill bindings
- role permission matrix
- knowledge-base default ID
- MCP tool namespace classification rules
Do not add business-specific intent names, tool descriptions, role names, MCP namespace prefixes, or knowledge-base IDs directly to harness Python code.
Knowledge Base
The current knowledge base is an external capability implemented locally under:
backend/app/infra/knowledge_base/
It owns document ingestion, parsing, chunking, embeddings, indexes, retrieval, weighted score fusion, context building, and source-grounded answer generation.
Harness consumes knowledge-base capability through the backend app API, not by importing app.
Native document-processing tools must use an opaque doc_id returned by an
application API. They must not accept local storage paths, raw file contents,
or guessed identifiers. The app owns upload validation and the ingestion
pipeline; Harness only invokes its authenticated workflow boundary.
Current flow:
harness RAG tool
-> HTTP POST /api/rag/search or /api/rag/query
-> app/api rag route
-> app/svc service
-> app/infra/knowledge_base
If the knowledge base later moves to a standalone service, keep this boundary and replace the app-side infra implementation with an HTTP or MCP adapter.
MCP Placement
MCP is split by direction:
backend/harness/mcp/: MCP clients used by the agent runtime.backend/app/api/mcp/: MCP servers exposing backend app capabilities.
backend/harness/mcp intentionally has no __init__.py so it does not shadow the official top-level mcp SDK package. Import local MCP code as harness.mcp.*.
MCP tool classification is configuration, not harness code. Use mcp_tools.rules in the runtime profile for app-specific prefixes and permission mappings.
Operations MCP servers must use a standard transport (Streamable HTTP or stdio), declare input types and risk annotations, bind local development servers to loopback, validate Origin for HTTP transport, and return expected provider/business failures as MCP tool execution errors. Do not expose provider credentials, database internals, or agent chain-of-thought in a tool result.
Persisted Cron tasks are app capabilities. Scheduler MCP tools live under
app/api/mcp/scheduler/; Harness discovers them through harness/mcp/ and
never implements an app-service HTTP adapter as a local tool plugin. MCP may
create, list, or cancel platform tasks, but it must not execute them. Execution
belongs exclusively to the independent Scheduler/Worker process, which claims
tasks atomically and calls the same app service used by direct API/MCP
operations. Do not use OS-specific task schedulers or API-process background
threads.
Use one shared Scheduler Core and one shared scheduler_tasks/scheduler_task_runs data model across platforms. A platform contributes only a ScheduledTaskExecutor adapter that validates and executes its own payload. Platform skills expose creation of platform-specific scheduled actions; a generic Scheduler skill exposes cross-platform task inspection and cancellation. Do not duplicate Cron parsing, lease handling, worker loops, or run-history persistence in platform skills.
Shared scheduler source belongs in app/scheduler/. Its standard five-field Cron parser supports names, lists, ranges, steps, timezone-aware next-run calculation, and Vixie day-of-month/day-of-week matching. Scheduler tools are App MCP tools; Harness reaches them only through its MCP client and dynamic tool registry.
User History And Audit
User queries and user-visible operation history are backend audit records, not tools and not harness memory. The backend app must persist the request identity, session/correlation ID, final run outcome, and tool/MCP call records in the app-owned agent_* collections. Dige provider request/response facts belong in dige_api_calls.
For Dige, dige_devices is the latest real-time provider observation, dige_device_state_history is immutable provider-observation history, and dige_device_operations is immutable control and verification history. App-only audit routes may query these collections; they must not be registered as MCP tools or loaded into Harness skills.
Harness may return a normalized RunResult over HTTP, but it must not import app repositories or write app audit collections. The app records the result after crossing the harness HTTP boundary.
Harness routes are named dige, scheduler, rag, and chipchat. Use these stable route and task-domain names in the runtime profile, Skill bindings, audit fields, and UI capability switches. The Scheduler route is platform-neutral: it persists a future natural-language goal and the due run independently selects its business route. Platform implementation modules may retain their own names, but they must not become agent routes unless explicitly added to this catalog.
Timed work never runs inside the API process. Add a dedicated scheduler/worker process entrypoint that reuses app/svc, app/domain, and app/infra; do not add a user-facing scheduler capability unless a documented platform requires one.
Local service topology is fixed: API 8000, Operations MCP 8100, Harness 9011, and the scheduler worker has no HTTP port. API-to-Harness loopback clients must set trust_env=False; inherited proxy variables must never intercept local service calls.
For Dige controls, provider API responses are the authority. MongoDB room/device snapshots are only audit/cache data and must not be used to decide whether a live operation succeeded or to fabricate a post-control state.
Skills
Skills live outside the harness runtime package:
backend/skills/
public/<skill-name>/SKILL.md
custom/<skill-name>/SKILL.md
harness.skills.loader.SkillLoader discovers backend/skills by default. A custom skill with the same name overrides a public skill.
Skill frontmatter must define name, description, allowed-tools, and, when a skill exposes more than one capability class, tool-categories. Every tool listed by tool-categories must also be listed by allowed-tools. allowed-tools is the sole source of tool-to-Skill ownership; an enabled tool may belong to at most one enabled Skill. Platform profile rules classify permissions and task domains only and must not bind a tool prefix to a Skill.
Routing receives only the compact index fields name, description, category, and path. It must not receive a Skill body, allowed-tools, or tool-categories. After planning selects a skill, the runtime loads its Markdown body once for the provider-native Tool Use execution context and exposes its configured tools and categories there. Reference files remain deferred until an explicit reference-loading capability is introduced.
At execution time, expose only the intersection of role-authorized tools and the active skill's allowed-tools. Skills may narrow tool visibility, but they must never grant permissions or override system-level runtime rules. A platform MCP tool may declare task_domain: platform, but it is loaded only by the configured platform Skill that owns its allowed-tools; it is not automatically mixed into business Skills. Framework-native tools such as resumable human input are the narrow exception and are injected by Harness itself.
Agent Graph Contract
Tool-assisted execution is one hand-written, framework-free graph:
START -> initialize -> model -> validate_model_output -> validate_tool_calls
-> tool_policy -> execute_tools -> append_tool_messages -> model
-> finalize -> END
-> fail -> END
messages is the model source of truth. The model adapter calls the provider-native Tool Use endpoint with the current registry-derived tools list and returns only an AIMessage(content, tool_calls). The graph never uses response_format, strict JSON action envelopes, ReAct JSON, or text / Markdown / regex extraction to infer a tool call. Routing is native ReAct: a non-empty tool_calls list enters the tool path; no tool_calls enters finalization. Every completed tool batch returns to the model node, without a separate required-tool flag or protocol fallback.
Every provider-native tool_call_id is preserved. The graph writes the assistant tool-call message before exactly one matching ToolMessage; schema, visibility, permission, policy, and execution errors also produce a matching structured ToolMessage. Validate inputs against the advertised JSON Schema without coercion. Keep MCP content, structuredContent, isError, and metadata in the tool record; failures remain structured observations, never fabricated successes.
Middleware is ordered and cross-cutting only: before_agent, before_model, wrap_model_call, after_model, before_tool, wrap_tool_call, after_tool, after_agent, and reverse-order on_error. It may log, trace, add dynamic context, summarize after model work, filter tools, count tokens, detect loops, transform errors, and publish events. Routing, confirmation, pause, authorization, and terminal status belong to explicit graph nodes or conditional edges.
Models, tools, MCP adapters, permissions, event publication, checkpointer, and store are injected as runtime dependencies. Use thread_id, the Harness Checkpointer, and explicit Resume values for pause/resume. invoke, ainvoke, stream, and astream must target the same graph; no separate streaming loop is permitted.
An application may configure human review on selected tools through its runtime metadata. The graph pauses before the call, persists the exact pending native tool calls, and waits for an application-owned decision record. After a decision, re-resolve identity and resume the same checkpoint by run id; do not re-plan the user request or replay a new agent turn. A review may approve, edit validated arguments, reject, or return a human response as that call's ToolMessage.
Verification
Run backend app tests from backend/:
python -m pytest tests
Run harness tests from backend/harness/ with backend, backend/harness, and backend/shared on PYTHONPATH:
python -m pytest tests
Before finishing backend architecture work, verify:
backend/appcontains onlyapi,svc,domain, andinfraas main source directories.backend/harnesshas no imports fromapp.- harness production prompts and default profile contain no app-specific business examples.
- app entrypoint imports as
app.api.main:app. - platform MCP entrypoints import as
app.api.mcp.<platform>.server:app.
