Skip to content

Writing a module

Everything the host runs is a module: the memory, the board, the team, HTTP, the scheduler. Write one to give your agents tools of your own. The host publishes them over MCP and gRPC for you, and governs what they may reach.

A module is a process that serves the pcx.module.v1 protocol on a socket the host gives it. It declares a manifest:

  • an id and a version;
  • its tools: a gRPC method, a name, a description and an effect (read, write, or one that acts outside);
  • the events it listens to, such as a tool being called or a turn ending;
  • its settings, as a protobuf message, which the app turns into a form;
  • the grants it needs (write_memory, read_conversation, network, filesystem, spawn) and the modules it uses.

The host refuses a module that asks for more than its entry grants, and checks every call against the grants at run time.

Implement the Module trait of pcx-module-api and serve it. The smallest example is the greet module in the repository (crates/pcx-greet): one tool, one setting, a process of about twenty lines.

Use the bindings: pcx-module for Python (PyO3) and for TypeScript (napi-rs). They own the protocol and hand your handlers protobuf messages, so you write only the tools. The same greet module in Python, and what the bindings do for you: Python and TypeScript modules.

On your own daemon, name it in daemon.toml. The host checks the file against its SHA-256, starts it, gives it its settings, and stops it with the daemon:

[[modules]]
id = "greet-py"
command = "/opt/pcx/greet-py"
sha256 = "<shasum -a 256 greet-py>"
grants = ["write_memory"]
uses = ["post-cortex.memory"]
config = { greeting = "Hello" }

Its tools then appear in the MCP tool list of every agent, and in a generic gRPC Invoke, with nothing else to publish. Change the entry and the daemon reloads it within two seconds.