Add configurable agent, MCP bridge, and Open Plugin Spec v1 support - #1
Draft
baladithyab wants to merge 1 commit into
Draft
Add configurable agent, MCP bridge, and Open Plugin Spec v1 support#1baladithyab wants to merge 1 commit into
baladithyab wants to merge 1 commit into
Conversation
…ility Ship `vigor-agent` (configurable agent with adapter registry, router, CLI) and `vigor-mcp` (MCP-as-ToolBackend bridge over stdio + http/sse) so one VIGOR agent can be wired declaratively from a YAML/JSON config instead of forking the runtime per use-case. Add Open Plugin Spec v1 manifests + generated SKILL.md to each adapter package so the same package also works as a cross-vendor plugin in Claude Code, Hermes, Strands, Goose, etc., without giving up the verifiable iterative loop. ADR-0014 covers the AgentConfig / Router design; ADR-0015 covers the plugin compatibility layer. https://claude.ai/code/session_0178GXqYgTfRDxKVm19UWV3T
baladithyab
added a commit
that referenced
this pull request
May 16, 2026
Closes ADR-0016 §3.2's gap: mutator tools were policy-only on the schema (ToolManifest.mutability) but no code enforced "mutators require capability grants". Per scout finding #3 (.overstory/specs/VIGOR-4293.md §4) and threat-model T4 (docs/security/threat-model.md:280) this was the #1 preventive mitigation for an operator allowlist mistake silently exposing a destructive upstream tool (e.g. neka-nat/freecad-mcp `execute_code`). Changes: - vigor-core/interfaces.py: - Add `RunContext.tool_capabilities: frozenset[str]` (default-empty). - Extend `ToolBackend.call_tool` ABC with `*, capabilities: frozenset[str] | None = None`. - vigor-mcp/backend.py: - `_ServerHandle.get_manifest` returns the cached `ToolManifest` for a tool_id (uses the existing `list_tools` cache; one-shot fetch). - `MCPToolBackend.call_tool` rejects mutator calls whose tool_id is not in `capabilities` with `ToolResult(status="failure")`. Observer tools always pass. Allowlist gate runs first (unchanged behavior). - Refactored gate logic into `_gate_call` helper to keep the dispatch path within the project's PLR0911 (≤6 returns) limit. - vigor-runtime/orchestrator.py: - `Orchestrator(tool_capabilities=...)` constructor param threads through to the per-run `RunContext`. Default-deny: empty frozenset. - Test backends (NullToolBackend, _SpyTools, _RecordingToolBackend, _CountingToolBackend, _MinimalTools): updated `call_tool` signatures to match the new ABC. - Tests: - test_backend.py: 6 new mutator-gate tests — observer always-passes, mutator denied without/with-empty/with-mismatched cap, mutator passes with matching cap, denial does not roundtrip the server. - test_orchestrator.py: 2 new tests — default capabilities are empty, constructor-passed capabilities surface on `RunContext`. Quality gates: 156 passed / 1 skipped; ruff clean; mypy clean.
baladithyab
added a commit
that referenced
this pull request
May 16, 2026
…ADR-0035 §Negative #1, VIGOR-c2ec) Layered in-process guardrail on top of VIGOR-aa1c's cross-process advisory lock. A second Orchestrator.run / .resume on the same archive root within one process now raises ArchiveBusyError immediately, before any archive I/O. - vigor_core.errors.ArchiveBusyError: sibling of ArchiveLockedError, not a subclass — busy = same-process re-entry (caller error), locked = peer process holds OS lock (potentially transient). Distinct retry semantics. - vigor_core.archive._ActiveRunRegistry: threading.Lock-protected set of resolved archive roots, atomic check-and-insert. Mirrors _LockRegistry's pattern (mx-7ce41e). Re-exported from vigor_core to match ArchiveLockedError's public surface convention. - RunArchive.claim_active_run(): contextmanager idiom — release on every exit path including exceptions. Adapter export() paths constructing transient RunArchive(run_dir.parent) are unaffected (mx-514b28); the guard is at Orchestrator.run, not RunArchive.__init__. - Orchestrator.run / .resume: 'with self._archive.claim_active_run():' wraps both archive I/O (write_task / read_checkpoint) and _execute, so busy fires before write_task per AC #2. - Tests: 5 new — concurrent gather raises busy, sequential succeeds, export-during-run still works, marker released on failure, sibling type relationship. codex review: confirmed (a) correct sibling typing, (b) export path preserved, (c) thread-safe under asyncio. No P0/P1 findings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR introduces a declarative configuration system for VIGOR agents, enabling multi-adapter composition, MCP server integration, and Open Plugin Spec v1 compatibility. It adds two new packages (
vigor-agentandvigor-mcp) and extends the core with agent configuration schemas and plugin helpers.Key Changes
New Packages
vigor-agent: Configurable VIGOR agent that loads
AgentConfig(YAML/JSON), instantiates adapters and backends, routes tasks across multiple adapters, and manages a run archive. Includes:AgentOrchestrator: thin wrapper wiring config to the runtimeAdapterRegistry: instantiate and look up adapters by IDRouter: resolve tasks to adapters via modality/domain matching or explicit routingFactoryRefloader with allowlist-based supply-chain gatingvigor-mcp: Bridge exposing Model Context Protocol servers as a
ToolBackend. Supports stdio, HTTP, and SSE transports via the official MCP SDK. Sessions are lazily opened and held for the agent lifetime to amortize connection costs.Core Extensions (vigor-core)
AgentConfig schema (
vigor.agent_config.v1): Declaratively wires adapters, backends, MCP servers, and routing policiesAdapterSpec: factory ref + modalities/domainsBackendSpec: factory ref for per-task backend instantiationMCPServerSpec: stdio/HTTP/SSE server declarations with tool allowlistsRoutingPolicy: modality_match / domain_match / explicit / single strategies with per-task overridesPlugin helpers (
vigor_core.plugin):OpenPluginManifest: Pydantic model for Open Plugin Spec v1 core fieldsexport_plugin_json(): serialize manifest to JSONexport_skill_md(): auto-generate SKILL.md from registered IR schemas (guards against drift)SkillTemplate: dataclass for skill metadataIR registry (
vigor_core.registry):register_ir(): register IR models for schema exportget_ir_model(): retrieve registered model by kindexport_json_schema(): generate JSON Schema from IR modelRunContext enhancement: added optional
tools: ToolBackendfield for ambient tool accessAdapter Updates
All three adapters now ship Open Plugin Spec v1 manifests:
.plugin/plugin.json: declares skills and metadata.plugin/vigor.json: Python factory ref for VIGOR loopSKILL.mdfiles in skill directories (photo-edit-recipe, cad-parametric, manim-scene)Each adapter's IR module now calls
register_ir()at import time to enable schema export.Testing & Tooling
scripts/regen_skills.py: regenerate all SKILL.md files from IR schemas (CI guard against drift)vigor-runtimeorchestrator to accept optionalToolBackendinRunContextDocumentation
Implementation Details
vigor_harness.evaluatorpattern with allowlist gating for supply-chain securityAsyncExitStackfor clean lifecycle management; one session per server, held for agent lifetime.plugin/plugin.json+ optional.plugin/vigor.jsonand on-disk skill/MCP pathsRoutingPolicy.overridesdicthttps://claude.ai/code/session_0178GXqYgTfRDxKVm19UWV3T