ADR-0164: Navin library activated per project, project rules, MCP servers and channels attached to a project
Context
The platform reuses the Navin code (navin-ai-v2/navin). The Navin package holds 265 skills (skills/), 17 plugins (builtin_plugins/), 20 commands (builtin_commands/), 14 agents (builtin_agents/), the marketplace.json catalogue, 31 MCP server presets (webui/mcp_presets_api.py, MCP_PRESETS), 10 messaging channels (channels/*.py and their setup contract channels/_setup.py) and the reading of the project rules of the coding agents (agent/project_rules.py). The clients of the platform must be able to reuse every one of them in their projects, with tenant then project isolation, without a workstation where Navin is installed.
Decision
- Versioned copy:
tools/navin_library/sync.pycopies the library intocatalog/navin(skills, plugins, commands and agents under their folder names,marketplace.json), extracts without importing the Navin code (astmodule) the MCP presets (mcp-presets.json), the channel contracts (channels.json) and the rule sources (rule-sources.json), and writesindex.jsonwith the sha256 digest of every item. Long dashes become-on copy.--checkfails when the copy no longer matches the source. The folder is never edited by hand. - Activation per project (V197,
eai.navin_library_activations, forced RLS): an activated skill is registered in the Skill Registry of the tenant with the signaturenavin-library:<name>(signernavin-library), verified byeai.domains.skills.signingagainst the SKILL.md digest of the index; the Skill Loader serves it like any signed skill. A plugin activates its skills, commands and agents (columnvia_plugin) and removes them with it. A library skill no project uses any more becomesdeprecated. - MCP per project:
eai.mcp_serversandeai.channelsgetproject_idandpreset. A server created from an HTTP preset goes through the existing MCP gateway; a secret field is only accepted as anopenbao://orenv://reference, and the new authentication typequery_paramadds the secret parameter at call time, never in the stored URL. A stdio preset runs where its command runs: the MCP page of the Navin Manager (nm.mcp_servers, V068, permissionsmcp:readandmcp:manage) manages it per tenant and project, tests the connection (initialize, tools/list) and seals its secrets with AES-256-GCM; the Control Plane then registers it by its HTTP endpoint. - Reusable channels: the channel contract accepts discord, telegram, matrix, mattermost and signal, and
spec.connection(provider,adapter,settings,secret_refs) names the Navin adapter. The installation checks the setup contract (fields, kinds, choices, requirements, secrets by reference only). The channel bridge of the Python SDK (enterprise_ai.channels.bridge) relays the messages of an adapter toPOST /v1/channels/{name}/inbound. - Project rules (V197,
eai.project_rules): import of.navin/rules/*.md,.cursor/rules/*.mdc(alwaysApply, description, globs),.cursorrules,.clinerules,.windsurfrulesand.github/copilot-instructions.md;GET /v1/projects/{id}/rules/promptgives the Navin prompt section (always on rules inlined and clipped, conditional rules listed with their globs).
Alternatives considered
- Importing the
navinPython package into the Control Plane: it brings the whole Navin workstation and its runtime. Copying files and extracting withastneeds the standard library only. - Storing the preset secrets in the Control Plane tables: agent secrets stay in OpenBao or the Credential Broker, never readable by an agent.
Consequences
A new Navin version is taken by running tools/navin_library/sync.py again; test_navin_library.py fails while the index, marketplace.json and the copied files disagree. The copied Navin code carries the licence of the navin-ai-v2 repository, published by Navinspire IA, publisher of the platform.
Evidence
services/control-plane/tests/test_navin_library.py, services/control-plane/tests/test_navin_library_projects.py, navin-manager/server/tests/test_mcp_servers.py, navin-manager/ui/src/test/mcp.test.tsx, the conformance tests of the four SDKs.