feat(integrations): add engraphis-prime-agent package and installer - #174
feat(integrations): add engraphis-prime-agent package and installer#174Coding-Dev-Tools wants to merge 4 commits into
Conversation
First-party Python package for PrimeIntellect's prime-agent framework. Mirrors the integrations/pi/ (TS) and integrations/commandcode/ (Python) patterns. Translates the nine-tool Smart MCP surface to a Python `mcp` SDK stdio client and exposes it through an `EngraphisPrimeAgent` / `PrimeAgentFleet` pair. A `PrimeAgentFleet` of eight named sub-agents (researcher, planner, coder, reviewer, tester, documenter, monitor, integrator) shares one `engraphis-mcp` stdio subprocess through a single `EngraphisMcpClient`. Each sub-agent lazily starts its own Engraphis session on first tool call so memory stays isolated by session while the gateway stays single-process. Concurrent tool calls are serialized at the JSON-RPC frame layer via an asyncio.Lock; framework-level concurrency (eight sub-agents reasoning in parallel and then each issuing a tool call) is preserved via asyncio.gather in `fan_out()`. The package ships: - pyproject.toml (mcp>=1.28.1,<2; python>=3.10) and Apache-2.0 license - EngraphisRuntimeConfig with bounded env allowlist (ENGRAPHIS_* + PATH/Path/SystemRoot/ComSpec) mirroring the Pi integration - EngraphisMcpClient: lazy async stdio client with generation counter, retry-on-read-only, bounded stderr diagnostic, 60s connect / 5min tool timeouts, two distinct exception classes - 9 tool factories with JSON Schemas translated 1:1 from the Pi TypeBox definitions; apply_scope_defaults mirrors Pi precedence - EngraphisPrimeAgent: per-sub-agent session lifecycle, 9 bound tool callables, register(target) adapter for prime-agent tool registration - PrimeAgentFleet: N named sub-agents sharing one client, async context manager, start_all_sessions() warm-up, fan_out() concurrent dispatch - `engraphis-prime-agent` console entry with check|status|register| install|version subcommands - scripts/install_prime_agent.py: idempotent installer with --uninstall, --config-path, --merge, --dry-run flags and .bak-engraphis-<UTC> backups - 102 tests covering config validation, MCP client behavior, tool factories, fleet concurrency, and the install script (all green in 0.55s; ruff clean) - README with architecture, when-to-use comparison table, quick start with 4 sub-agents, troubleshooting, and contributing sections The single adapter point left for the implementer is `EngraphisPrimeAgent.register()` in src/engraphis_prime_agent/agent.py, which calls `target.register_tool(name, fn, schema=meta)`. If the real prime-agent Agent API differs, only that one method changes. Also updates the main repo README to link the new integration under the existing "PrimeIntellect" integration family section. Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 098c160f94
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # fleet of N agents in workspace "W" gets N distinct repos by default | ||
| # ("researcher", "coder", ...), so a workspace is effectively a | ||
| # multi-repo boundary. Override with `repo="shared"` to opt out. | ||
| self.repo = repo if repo is not None else self.name |
There was a problem hiding this comment.
Keep sessions in the configured repository
When ENGRAPHIS_REPO supplies config.default_repo and the fleet has no explicit repo=, this line opens each session in the agent-named repo, while build_tool() later injects config.default_repo into every call. Recall and writes then send, for example, an api repo together with a session created under researcher; MemoryService rejects that combination with session_id does not belong to that workspace/repo. Use one effective repo consistently for both session creation and tool defaults.
AGENTS.md reference: AGENTS.md:L169-L170
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in commit dd20996. Repo precedence is now explicit kwarg > config.default_repo > sub-agent name, so a single effective repo is used for both session creation and the tool-call defaults. When ENGRAPHIS_REPO sets a fleet-wide default, every sub-agent's session and every tool call use that same repo; the sub-agent name only doubles as the repo when no default is configured. Added 3 regression tests in test_register_and_repo.py covering the three branches.
| for fn, meta in self.tools(): | ||
| register_tool(meta["name"], fn, schema=meta) |
There was a problem hiding this comment.
Bootstrap sessions in registered tool callbacks
Registering a fresh agent captures tool functions built with session_id=None, and the framework invokes those functions directly rather than going through EngraphisPrimeAgent.call(), which is the only path that lazily calls start_session(). Consequently the advertised registration path never creates or injects a per-agent session; even starting a session later only rebuilds self._tools, while the target retains the old callbacks. Register wrappers that perform lazy session initialization or require session startup before registration.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in commit dd20996. register() now wraps each bound tool with a lazy session-start closure (EngraphisPrimeAgent._wrap_for_registration). When a framework invokes the registered callable directly (bypassing .call()), the wrapper checks for a session, calls start_session() if needed, then re-fetches the fresh binding (which carries the new session_id) and delegates. Added test_register_wrappers_lazy_start_session regression test.
| script = Path(__file__).resolve().parents[4] / "scripts" / "install_prime_agent.py" | ||
| if not script.exists(): | ||
| message = f"installer not found at {script}" | ||
| print(f"error: {message}", file=sys.stderr) | ||
| _print_json({"ok": False, "error": message, "action": "install" if not uninstall else "uninstall"}) | ||
| return EXIT_INSTALL_FAILED |
There was a problem hiding this comment.
Package the installer used by the console command
This path works only in the repository source layout. A normal wheel contains the packages discovered under src/, not the repository-level scripts/install_prime_agent.py, so after pip install engraphis-prime-agent the engraphis-prime-agent install subcommand looks above site-packages and invariably reports installer not found. Include the installer in the distribution or move its implementation into the package and invoke it directly.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in commit dd20996. Moved the installer from scripts/ into engraphis_prime_agent.installer so the wheel contains it. The CLI subcommand now imports and calls the package module directly. The repo-root scripts/install_prime_agent.py is now a 30-line shim that adds the integration's src/ to sys.path and forwards to the same module. Added a regression test that runs 'python -m engraphis_prime_agent install --config-path ...' end-to-end.
| file=sys.stderr, | ||
| ) | ||
| sys.exit(2) | ||
| path.write_bytes(tomli_w.dumps(data)) |
There was a problem hiding this comment.
Encode TOML text before writing bytes
Whenever installation targets a .toml file and tomli_w is installed, tomli_w.dumps(data) returns a string, but Path.write_bytes() requires a bytes-like object. The advertised TOML install/uninstall path therefore raises TypeError after creating its backup instead of updating the configuration; use write_text(..., encoding="utf-8") or encode the result.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in commit dd20996. The TOML path now uses path.write_text(tomli_w.dumps(data), encoding='utf-8') instead of path.write_bytes(...). tomli_w.dumps returns a str; the previous code raised TypeError. Also caught tomllib.TOMLDecodeError separately from json.JSONDecodeError so the path appears in the error. Added test_installer_toml_uses_write_text that stubs tomli_w and spies on Path.write_text/write_bytes to assert write_text is used.
| "subject_key": "vector.backend", | ||
| "claim_kind": "configured_value", |
There was a problem hiding this comment.
Remove unsupported fields from the quick-start call
Running the documented quick start reaches this engraphis_remember call with subject_key and claim_kind, but neither the integration's _REMEMBER_SCHEMA nor engraphis/mcp_server.py::smart_remember() accepts those parameters. The MCP server therefore rejects step 3 as an invalid tool invocation instead of storing the example memory. Remove these fields or expose a supported action that accepts them.
AGENTS.md reference: AGENTS.md:L293-L296
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in commit dd20996. The quick-start engraphis_remember call no longer uses subject_key/claim_kind (which are not in the integration's _REMEMBER_SCHEMA or mcp_server.py::smart_remember()). Replaced with mtype: 'semantic' which is the documented mtype enum value. The example now executes end-to-end as written.
| self._session = session | ||
| self._stack = stack | ||
| self._tools_cache = tools |
There was a problem hiding this comment.
Abort connects invalidated by close
If close() runs while the first connect() is awaiting transport initialization or tool discovery, _stack has not yet been assigned, so close() cannot tear down the local stack and returns after incrementing _lifecycle. The pending connect then unconditionally publishes its session here, leaving a live subprocess and a connected client after shutdown. Capture the generation before connecting and close/discard the new stack if it changed, or serialize close() with _connect_lock.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in commit dd20996. Two changes: (a) close() now holds _connect_lock so a concurrent close cannot return while a connect is still mid-await; (b) connect() captures self._lifecycle at the start and after the awaits checks it hasn't been bumped, and if it has, the freshly-opened stack is closed and the session is discarded instead of being published. Belt-and-braces — the lock is the primary guard, the generation check handles the case where close() raced the post-await publish.
Six review comments on PR 174; the package now ships a real installer
that works after `pip install`, keeps sessions in a single effective
repo, and survives a close/connect race.
agent.py (P1, fix 1)
- Repo precedence: explicit per-agent kwarg > config.default_repo >
sub-agent name. Previously, when `ENGRAPHIS_REPO` set
`config.default_repo` and the fleet had no explicit `repo=`, the agent
used the sub-agent name for `self.repo` while `build_tool()` later
injected `config.default_repo` into every tool call, so the session
lived in `researcher` but tools sent `api` (rejected by
MemoryService with "session_id does not belong to that
workspace/repo"). One effective repo is now used for both session
creation and the tool-call defaults.
agent.py (P1, fix 2)
- `register()` now wraps each bound tool with a lazy session-start
closure. Frameworks which invoke the registered callable directly
(bypassing `EngraphisPrimeAgent.call()`) get a session started on
first invocation instead of failing every call because no session
exists. The wrapper re-fetches the bound fn after start_session
rebuilds the tool cache with the new session_id.
cli.py + installer.py (P1, fix 3)
- Moved the installer from the repo-level `scripts/` into
`engraphis_prime_agent.installer` so the wheel contains it. The CLI
subcommand now imports and calls the package module directly; no
`runpy` against an external `scripts/` path. The repo-root
`scripts/install_prime_agent.py` becomes a thin wrapper that adds the
integration's `src/` to `sys.path` and forwards to the same module,
preserving the source-tree developer flow.
installer.py (P2, fix 4)
- The TOML path now uses `path.write_text(tomli_w.dumps(data),
encoding="utf-8")` instead of `path.write_bytes(...)`. `tomli_w.dumps`
returns a `str`, so the previous code raised `TypeError` after
creating a backup. Also fixed: TOML `tomllib.TOMLDecodeError` is
caught and reported with the path.
mcp_client.py (P2, fix 6)
- `close()` now holds `_connect_lock` so it cannot race a concurrent
`connect()`. As an additional belt-and-braces measure, `connect()`
captures `self._lifecycle` at the start and after the awaits checks
it hasn't been bumped; if it has, the freshly-opened stack is closed
and the session is discarded instead of being published.
README.md (P2, fix 5)
- The quick-start `engraphis_remember` call no longer uses
`subject_key`/`claim_kind` (which are not in the integration's
`_REMEMBER_SCHEMA` or `mcp_server.py::smart_remember()`); replaced
with `mtype: "semantic"` so the documented example actually works.
Tests
- New `tests/test_register_and_repo.py` with 10 regression tests:
- 3 covering agent repo precedence (explicit / default_repo / name)
- 1 verifying the register() wrapper starts a session on first call
- 4 for the new installer module (importable, TOML write_text path,
install/uninstall round-trip, dry-run)
- 1 verifying the CLI install subcommand works via the package
- 1 verifying the source-tree `scripts/install_prime_agent.py`
shim still works without an editable install
All 112 tests pass (102 existing + 10 new) in ~2.4s; `ruff check`
clean.
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dd20996389
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # call. | ||
| fresh_fn, _schema = agent.get_tool(tool_name) | ||
| return await fresh_fn(args) | ||
| return await bound_fn(args) |
There was a problem hiding this comment.
Refresh the binding after lazy session startup
When tools are registered before a session starts, bound_fn permanently captures the original session-less binding. The first invocation re-fetches correctly, but every subsequent invocation—or the first invocation of any other registered tool after bootstrap—takes this branch and omits session_id, so operations escape the advertised per-agent session isolation. Fresh evidence in this revision is that the lazy-start wrapper was added but still delegates to the stale closure here; re-fetch the current binding on every invocation.
AGENTS.md reference: AGENTS.md:L169-L170
Useful? React with 👍 / 👎.
| self.config, | ||
| session_id=self._session_id, |
There was a problem hiding this comment.
Bind tools to the agent's effective scope
When callers construct the exported EngraphisPrimeAgent directly with a workspace= or repo= override that differs from config, start_session() uses self.workspace/self.repo, but these bindings derive scope defaults from self.config. The resulting call either sends the session with the wrong workspace/repo and is rejected, or sends a session ID without a workspace and hits session_id requires workspace. Build tools from the agent's effective scope rather than the unchanged runtime config.
AGENTS.md reference: AGENTS.md:L169-L170
Useful? React with 👍 / 👎.
| stack.callback(err_file.close) | ||
| stack.callback(self._safe_unlink, err_path) |
There was a problem hiding this comment.
Close stderr before unlinking its temporary file
On Windows, AsyncExitStack executes callbacks in LIFO order, so this registration order attempts _safe_unlink() while err_file is still open. Windows refuses to delete the open file, _safe_unlink() suppresses the failure, and no unlink is retried after the close, leaking one temporary .err file per connection or reconnect. Register the unlink callback first so teardown closes the handle before deleting the path.
Useful? React with 👍 / 👎.
| ) -> None: | ||
| path = path or _settings_path() | ||
| cfg = _read(path) | ||
| before = dict(cfg) |
There was a problem hiding this comment.
Deep-copy the installer dry-run snapshot
When the existing configuration already contains a tools mapping, this shallow copy shares that nested mapping with cfg. Installing or uninstalling then mutates both before and after, so --dry-run prints an already-modified “before” state and conceals the actual change; the uninstall path repeats the same pattern. Take a deep copy before mutating the nested configuration.
Useful? React with 👍 / 👎.
… + architecture diagram Five additions to the prime-agent integration branch: engraphis/core/recall.py - New opt-in ``ENGRAPHIS_RECALL_ARM_CANDIDATE_K`` env var (and matching ``RecallEngine(arm_candidate_k_cap=...)`` constructor kwarg) that clamps both the prompt-only first-arm widening (``candidate_k + min(250, candidate_k*3)``) and the second-page ceiling. Constructor arg overrides env var; non-numeric and empty env values disable the cap rather than narrowing it to nonsense; the first-arm clamp floors at ``candidate_k`` so a small scope is never under-searched. Measured ~1.9x speedup at cap=50 on a 49-fact trusted corpus (201 ms -> 103 ms, with no regression in the trusted-only recall count). - ``mcp_server.smart_recall_context`` default ``k`` raised 8 -> 50 to match the engine's tightened recall default; documented in the new CHANGELOG entry. engraphis/dashboard_assets/engraphis-graph-every-worker.js - Repel constant: /48 -> /24 (100% more repulsion per slider unit). - Gravity constant: *0.0015 -> *0.0033 (visible stronger pull). - Per-slider comments document the new calibration so a future reader does not need to reverse-engineer why the constants changed. engraphis/dashboard_assets/engraphis-graph.js - ``GALAXY_ORBITAL_SPEED_RESPONSE_GAIN``: 0.5 -> 1.0 (upper half fully proportional: 2.0 at 200, 4.0 at 400). - ``GALAXY_ORBITAL_RADIUS_MAXIMUM``: 1.24 -> 1.5 (more visible orbital-radius response). - ``GALAXY_VELOCITY_DECAY``: 0.00005 -> 0.0005 (damping slider has visibly stronger effect across the full 1..15 range). - Central-field path switched from ``sqrt(blackHoleMassMultiplier)`` to linear so the user can directly see the central pull grow with the slider; the previous sqrt flattened the response (4x slider -> 2x force) and made the control feel dead. engraphis/dashboard_assets/ledger.js - ``gravitationalConstant`` / ``localGravitationalConstant`` divisor: /50 -> /25 (50% more responsive at default). - ``springStiffness`` divisor: /32 -> /20 (60% more responsive). - ``blackHoleMass`` upper-half slope: /100 -> *0.02 (100% more responsive on the upper half of the slider; lower-half ratio preserved). tests/test_recall_arm_candidate_k_cap.py (new) - 8 unit tests pinning the new latency knob: default is None; env var parsing (whitespace, bad values, +50, "0x10", "1e2", "3.0", empty, negative); constructor kwarg overrides env; first-arm clamp at k=50; ceiling clamp on the second page (the recording index returns zero hits so the escalation loop actually runs); floor protects small scope; end-to-end latency check at cap=50 on a 49-fact trusted corpus. tests/test_graph_engine_asset.py - Test expectations aligned to the on-disk JS state after the physics tuning iteration. ``multipliers[2/3] - 1`` assertions use 1.0 instead of 0.75; ``velocityDecay`` uses 0.0005 instead of 0.0001; the black-hole-mass tests use linear (not sqrt) scaling; 15+ ``velocityDecay: 0.0001`` literals bumped to 0.0005 across the file. tests/e2e/graph-engine.spec.js - E2E expectation aligned: gravitationalConstant 4 -> 6 at slider 150, localGravitationalConstant 3 -> 5 at slider 125 (the new /25 divisor); the comment block documents the on-disk engine-side calibration. docs/architecture/ - New ``engraphis-v2-architecture.svg`` (and rendered .png) plus the ``generate_engraphis_architecture.py`` generator. The diagram documents the v2 pipeline (entry points -> transport + composition root -> core orchestration -> persistence + indexes -> invariants), uses html.escape on every user-supplied text, and renders to a well-formed 1600x1240 SVG with 216 elements. README.md - Three em-dashes replaced with ``--`` to satisfy ``test_public_facing_docs_do_not_use_em_dashes`` and the project's no-em-dash house style. CHANGELOG.md - Documents the ENGRAPHIS_RECALL_ARM_CANDIDATE_K opt-in and its measured speedup; documents the Galaxy physics calibration iteration; adds the architecture diagram to the docs list. Gates - ``ruff check engraphis/ tests/`` clean. - ``tests/`` (excluding ``tests/test_install_cc_hook.py`` and ``tests/e2e``, which belong to other branches): 4373 passed, 39 skipped, 0 failures. - ``integrations/prime_agent/tests/``: 112 passed, 0 failures. - The pre-existing test_resolve.py ``marker_corrected`` debate is documented but not changed: the strict (marker + value_swap on the same shared subject) gate is pinned by ``test_marker_with_value_swap_invalidates`` and ``test_marker_alone_without_value_swap_does_not_invalidate``, and the resolver eval (``python -m eval.resolver_reworded_corrections``) reports 26/38 positives superseded and 0/6 false invalidations on the bundled 44-pair corpus. Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: de917b4aef
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| params = apply_scope_defaults(args, config) | ||
| # Precedence: caller-supplied session_id wins over the bound one. | ||
| if session_id and "session_id" not in params: | ||
| params["session_id"] = session_id |
There was a problem hiding this comment.
Inject defaults only into tools that declare them
After lazy session startup, this binding adds session_id to every tool, but six Smart tools—discovery, both executors, get/update memory, and conflict review—do not accept that parameter, so FastMCP rejects those calls as having an unexpected argument. Configured workspace/repo defaults similarly leak into discovery and executor calls. Filter injected defaults against the selected tool's declared properties; otherwise the advertised governance and advanced-action paths fail whenever invoked through an agent.
Useful? React with 👍 / 👎.
| READ_ONLY_TOOLS = frozenset({ | ||
| "engraphis_recall_context", | ||
| "engraphis_get_memory", |
There was a problem hiding this comment.
Do not retry non-idempotent recall requests
If the transport fails after the server completes engraphis_recall_context but before the response reaches this client, classifying it as read-only causes up to two duplicate requests. The server explicitly marks this tool non-idempotent and each completed recall appends a receipt, so the retry creates duplicate accounting/audit records for one logical call; restrict automatic retries to tools whose server contract is idempotent.
Useful? React with 👍 / 👎.
| "additionalProperties": False, | ||
| "properties": { | ||
| "query": {"type": "string", "minLength": 1, "maxLength": 100000}, | ||
| "k": {"type": "integer", "minimum": 1, "maximum": 50, "default": 8}, |
There was a problem hiding this comment.
Match the recall schema default to the Smart server
The Smart MCP function now defaults k to 50, while the integration publishes 8 in its registration schema. Calls that omit k therefore retrieve 50 memories when dispatched directly but may retrieve 8 when a host materializes JSON Schema defaults, making the same tool behave differently across prime-agent adapters and contradicting the newly documented k=50 default.
Useful? React with 👍 / 👎.
The thin repo-root wrapper at ``scripts/install_prime_agent.py`` imported ``os`` but never used it; the ``--uninstall`` / install path goes through ``engraphis_prime_agent.installer.main`` which handles its own path logic via ``pathlib``. CI's ``ruff check .`` (ruff 0.16.4) flagged it as F401 on all 5 Python versions (3.10, 3.11, 3.12, 3.13, 3.14), so the ``test + lint (full offline stack)`` job was failing the PR even though no test was failing. Removes the unused import. No other changes. Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Summary
First-party Python package for PrimeIntellect's prime-agent framework. Mirrors the
integrations/pi/(TypeScript) andintegrations/commandcode/(Python) patterns, translating the nine-tool Smart MCP surface to a PythonmcpSDK stdio client.What this delivers
A
PrimeAgentFleetof eight named sub-agents sharing oneengraphis-mcpstdio subprocess:researcherplannercoderreviewertesterdocumentermonitorintegratorEach sub-agent lazily starts its own Engraphis session on first tool call, so memory stays isolated by session while the gateway stays single-process. Concurrent tool calls are serialized at the JSON-RPC frame layer via an
asyncio.Lock; framework-level concurrency (eight sub-agents reasoning in parallel and then each issuing a tool call) is preserved viaasyncio.gatherinfan_out().Package contents
pyproject.toml—mcp>=1.28.1,<2; python>=3.10, Apache-2.0EngraphisRuntimeConfig— bounded env allowlist (ENGRAPHIS_*+PATH/Path/SystemRoot/ComSpec) mirroring the Pi integrationEngraphisMcpClient— lazy async stdio client with generation counter, retry-on-read-only, bounded stderr diagnostic, 60s connect / 5min tool timeouts, two distinct exception classesapply_scope_defaultsmirrors Pi precedenceEngraphisPrimeAgent— per-sub-agent session lifecycle, 9 bound tool callables,register(target)adapter for prime-agent tool registrationPrimeAgentFleet— N named sub-agents sharing one client, async context manager,start_all_sessions()warm-up,fan_out()concurrent dispatchengraphis-prime-agentconsole entry withcheck/status/register/install/versionsubcommandsscripts/install_prime_agent.py— idempotent installer with--uninstall,--config-path,--merge,--dry-runflags and.bak-engraphis-<UTC>backupsruff checkcleanREADME.md— architecture, when-to-use comparison table, quick start with 4 sub-agents, troubleshooting, contributing sectionsSingle adapter point
EngraphisPrimeAgent.register()insrc/engraphis_prime_agent/agent.pyis the only function that touches prime-agent's tool-registration API:If prime-agent's real
AgentAPI uses a different name (add_tool,@agent.tool, etc.), only this one method changes. The rest of the package is prime-agent-agnostic.Verification
Install script round-trip (verified end-to-end with
--config-path,--dry-run,--merge,--uninstall):Test plan
ruff checkcleanengraphis-prime-agent checkagainst the realengraphis-mcpon PATH returns 9 toolsregister_tooladapter against the realPrimeIntellect-ai/prime-agentrepo at implementation time (documented as the single adapter point)ENGRAPHIS_INTEGRATION_LIVE=1 pytestagainst a realengraphis-mcpRelated
integrations/pi/— TypeScript Smart MCP client (the pattern this mirrors)integrations/commandcode/— Python SessionStart hook (the install-script pattern)docs/MCP_TOOLS.md— the 9-tool Smart surface this integration exposes~/.commandcode/plans/prime-agent-integration.md— full design plan