Setting up Famulus
Famulus is set up progressively. The initial installation establishes the common machinery required by every skill. Accounts, credentials, and recurring jobs are configured later, when a workflow first needs them.
This division keeps the initial installation small. If you need only the research and writing skills, you do not have to configure Google or a native job scheduler. You can add those capabilities later without reinstalling the system.
1. Install the core system
Famulus needs the host plugin plus a Python 3.11 or newer interpreter with a
functional pip.
Famulus runs every skill through the dispatcher server, and the dispatcher
executes each skill's code with its own interpreter. That interpreter is the
dispatcher runtime, and bootstrap-dispatcher-runtime is the skill that provides
it. Keeping it separate means the Python you use for your own work is never
modified, and upgrading or replacing that Python cannot break Famulus.
Two things follow from the dispatcher running everything with one interpreter.
The packages in requirements-mcp.txt are what the server needs to start at all. A
skill's own dependency — marker-pdf for PDF conversion, say — is installed
into the same runtime, because that is the interpreter the dispatcher will run
that skill with. Both belong to bootstrap-dispatcher-runtime.
It also runs without MCP. That is what lets it repair the very thing MCP needs in order to start.
What it does: verifies the host's bare python, resolves the platform-native
Famulus runtime location, builds it, installs only the declared
packages, verifies the result, and reports what remains for you to do.
What it does not do: install Python, alias or shim any command, edit your shell
profile or host settings, bootstrap pip, use uv, or install anything into an
interpreter other than the dispatcher's. When it cannot finish inside those
limits it stops and tells you exactly what it needs from you, which for a
machine with no suitable Python means installing one and giving it the path.
1.1 Install the host plugin
In Claude Code, the plugin can be installed from inside a session:
/plugin marketplace add MoeenNehzati/famulus
/plugin install famulus@nullkit
It can also be installed from a terminal:
claude plugin marketplace add MoeenNehzati/famulus
claude plugin install famulus@nullkit
For Codex, use:
codex plugin marketplace add MoeenNehzati/famulus --json
codex plugin add famulus@nullkit --json
Restart the host after installing the plugin so that it discovers the new skills and MCP declaration.
The two hosts use different native plugin manifests. Claude reads the inline
famulus_dispatcher declaration from .claude-plugin/plugin.json and maps
${CLAUDE_PLUGIN_DATA} to FAMULUS_PLUGIN_DATA. Codex reads the root Agent
Plugins plugin.json and the conventional root mcp.json, which maps
${PLUGIN_DATA} to the same normalized variable. Both declarations also pass
an explicit FAMULUS_HOST and start mcp_launcher.py. The launcher consumes
only this normalized host and plugin-data context; it does not translate
host-native variables itself.
This MCP registration is separate from lifecycle-hook registration. Claude
currently discovers the packaged hooks/hooks.json. The tested Codex release
accepts the root Agent Plugins MCP declaration but does not execute that
packaged hook file, so Codex does not currently receive Famulus's automatic
SessionStart diagnosis. See LLM Lifecycle Hooks for the
current host boundary.
1.2 Verify the dispatcher runtime
Confirm that python is Python 3.11 or newer and that python -m pip works.
Use bootstrap-dispatcher-runtime for the launcher's exact missing-runtime
diagnosis:
Famulus MCP startup's dedicated dispatcher runtime is missing at ...
Do not infer that route from a generic MCP startup or handshake failure. Report
the launcher's actual error first. The launcher also checks whether the
existing runtime satisfies requirements-mcp.txt; when it does not, it emits a
distinct requirements diagnosis and the bootstrap clue rather than starting
the server.
The plugin manifest starts the stdlib-only launcher through bare python.
Bootstrap creates and verifies the interpreter at the platform-native
FamulusPaths.venv_python_path; the launcher resolves that same path and starts
mcp_server.py with it. No PATH, alias, shim, shell-profile, state-file, or
host-setting change is required. A fresh host launch uses the dedicated venv.
A previous successful setup does not by itself show that the shared tool is reachable in the current host session. The dispatcher reference explains routing and authorization, while the security and privacy boundary explains what setup state is retained.
1.3 Let workflows request their own setup
Installing Famulus does not connect accounts or enable recurring jobs. Setup is demand-driven: when a requested workflow needs an unconfigured capability, Famulus guides you through only that capability and its prerequisites, verifies the result, and continues the original request.
Setup is checked at the MCP root and at every actual
PythonMachineInterface.dispatch() before its target launches. An unmanaged
target simply proceeds without contacting the setup manager. These checks are
dynamic: uses_interfaces declarations are not statically traversed, so an
unused branch does not request setup. Standalone dispatch chains also perform
these checks, but only MCP turns a refusal into a setup continuation.
If a nested call needs setup, the refusal travels through the existing private
process diagnostic channel with an outer-to-inner call_path of interface
IDs. The MCP root validates it and returns the existing setup continuation or
error result. For setup_required, the continuation identifies the original
outer MCP request, not the blocked child. setup_busy identifies the active
flow, its recorded owner process, and the exact guarded recovery interface.
For setup_required or setup_managed, pass the returned manager object
unchanged to famulus_dispatcher.invoke_security_2; it includes the original caller.
The outer workflow may already have done work before reaching the blocked child. Retrying the outer request after setup can repeat that work; nested setup checking does not make the workflow transactional or exactly-once.
If setup is interrupted, tell the LLM to invoke the returned recover-busy
interface. The LLM invokes it through the Famulus MCP dispatcher, which first
checks the flow's process lease rather than trusting its recorded PID.
Configure and operate persistent features through their owning skills, and use
the Personal Assistance Quickstart and
Automation Quickstart for normal workflow order.
Everything else is opt-in and demand-driven. A Famulus skill is an Officina
node. A public export named exactly .interface.setup is managed automatically
for Boolean whole-module readiness with no separate opt-in required.
A managed setup establishes only state owned by that node. Required setup of
another managed owner is declared with setup_requires_setup_of; the manager
runs that prerequisite first in the same finite flow. Production ownership is:
connect-google.interface.setup: shared Google Desktop OAuth client and one selected Drive+Calendar+Gmail credential.online-calendar.interface.setup: Calendar-owned binding and live Calendar verification; requires Connect Google.cloud-files.interface.setup: Drive-owned binding,assistantroot config, and root existence; requires Connect Google.email-client.interface.setup: Gmail account binding plus IMAP and SMTP-auth verification; requires Connect Google.list-manager.interface.setup: canonicaltodoandtriagecloud lists; requires Cloud Files.llm-wakeup._rtx.interface.setup: feature-owned wakeup integration.
A Markdown setup is an active manager step while its instructions run. Ordinary
managed calls would therefore see setup_busy. For only the reviewed helper
calls named by the current Markdown production binding, the caller passes the
current flow id as setup_flow_id to the exact security-tier tool declared for
that interface. MCP asks the
manager to authorize that exact (flow, interface, version) and then executes
the already-authorized dispatcher target. No nested setup flow is created, and
calls without setup_flow_id keep the normal preflight behavior.
Calls whose caller or terminal target module is exactly
setup-interface-manager._rtx bypass the per-call setup gate. This narrow
exception lets the manager's control routes, actions, and verifiers operate
without recursively requesting setup; similarly prefixed module names do not
receive that bypass.
Generic discussion about setup, installation, configuration, or teardown does not activate the manager.
When an ordinary managed interface is requested, its generated gate and the Famulus MCP preflight use the same lifecycle:
status@1classifies the target asunmanaged,ready,setup_required, orsetup_busywithout changing claims.- A pending target switches through
begin@1to the prerequisite-first stack.run-markdown@1returns the exact declared instructions;run-python@1runs its fixed action and verifier.settle@1runs a verifier when one exists; a verifier-free Markdown step records completion when the caller settles only after its instructions succeeded. - After the flow reports ready, the caller rechecks
status@1, callsauthorize@1, and resumes the original request exactly once only whenresume_originalis true.
The caller retains original arguments and stdin during this switch. The manager persists only continuation identity and setup receipts; helper-call arguments, stdin, environment, verifier output, and dispatcher diagnostics are not stored in the setup ledger.
You therefore do not configure the whole system in advance. Setup follows actual use and asks only for state needed by the capability being reached.
1.4 Persisted state and live MCP readiness are different
The only persisted setup state is the manager's schema-versioned JSON ledger at
the single absolute setup-status path returned by
common.interface.famulus-paths-get@1. The manager creates and updates that
file through its confined atomic adapter; no public manager route accepts a
ledger path. An exact interface/version receipt means the declared verifier
passed. Its required_by roots record which managed workflows still claim that
state. MCP never reads or writes this ledger directly; setup-interface-manager
remains its sole authority.
The ledger does not say whether the shared Famulus MCP process is currently
reachable. Live famulus_dispatcher.invoke_security_0,
famulus_dispatcher.invoke_security_1, or famulus_dispatcher.invoke_security_2
availability is the MCP readiness signal, and
MCP startup does not overwrite the setup ledger. A malformed or unsupported
ledger fails closed instead of being treated as ready.
Missing or stale prerequisites rerun only the affected dependent suffix. For a
leaf -> parent -> root setup order, a stale parent reruns parent and root while
retaining the exact leaf. While no flow is active,
setup-interface-manager._rtx.interface.invalidate@1 removes a selected
receipt and every managed dependent receipt; the next use rebuilds the current
closure from verified state.
1.5 Teardown and recovery
Exact managed setup and teardown calls are redirected to begin@1; they never
launch a lifecycle interface directly. Teardown walks the setup order in
reverse. It runs an external teardown only after the last root releases a
receipt. If another root still claims a shared dependency, the manager removes
only the current root's claim. A teardown verifier must return success before
the receipt is removed, and teardown never resumes an ordinary request.
Only one ledger-mutating flow can be active. A second action receives
setup_busy with the existing flow identity, recorded owner, and exact
setup-interface-manager._rtx.interface.recover-busy route. Invoke it without
--force first. It clears the exact flow only if its process lease is free.
If it returns setup.owner_active, the owner still appears live; use --force
only after the user explicitly confirms interruption. An ownerless legacy flow
cannot be proved stale and therefore exposes only forced recovery.
After an interruption, the owning flow may receive recovery-required; its
setup-interface-manager._rtx.interface.recover@1 accepts only retry or
cancel: retry checks the verifier before rerunning the exact current step;
cancel removes claims added by completed steps and clears the flow without
guessing whether the interrupted external action finished. Invalidation is
refused until the active flow is recovered or cancelled.
Persistent features remain independently owned: install-launchers configures
interactive launchers, recurring-tasks configures recurring work,
llm-wakeup configures due-session delivery; Connect Google owns shared
authorization and service skills own service configuration. Each installs only
its own residual declared packages.
1.6 Tear down all managed setup state
Call setup-interface-manager._rtx.interface.teardown-all with no arguments
and no stdin to tear down every valid managed setup receipt in the selected
repository context. The manager plans dependents before prerequisites, runs
each receipt's declared teardown and verifier, and retains the canonical empty
ledger when the operation completes. Its response always has original: null
and resume_original: false.
An interrupted operation remains recoverable through recover@1; retry checks
the current verifier before rerunning, while cancel follows the persisted-flow
rules above. To tear down only one managed root and its unshared closure, keep
using begin@1 with the teardown operation and that root's setup interface.
This route covers only valid managed setup receipts in the selected context. It is not plugin/runtime uninstall or general purge, and it does not remove unmanaged, host, credential, remote-authority, historical, or irreversible effects. Each admitted owner separately proves effect reversal, repeat safety, and recovery; manager verifier success alone proves none of those properties.
1.7 Remove Famulus
If you want to clean up Famulus's managed setup state and run every declared
local teardown, tell your LLM to invoke
setup-interface-manager._rtx.interface.teardown-all with no arguments or
stdin while the plugin is still installed. The LLM will send the interface
call through the Famulus MCP dispatcher using the currently declared version.
Let that operation complete before removing the plugin. Then run the standard
removal command for each host where Famulus is installed:
# Claude Code
claude plugin uninstall famulus@nullkit --scope user
# Codex
codex plugin remove famulus@nullkit --json
Restart the host after removing the plugin. Teardown does not revoke Google access, delete service or cloud data, or remove unmanaged files or installations that predate the plugin. Remove those separately if desired.
2. Connect personal-assistant services
The personal-assistant subsystem is organized around persistent todo and
triage lists. Google Drive stores those lists and daily plans, Gmail supplies
messages from which email-triage can identify actions, and Google Calendar
supplies commitments for daily-plan. The
Personal Assistance Quickstart explains
how these services feed the shared list-centered system and gives the
recommended starting sequence.
Ask the assistant:
Connect Famulus to Google.
Famulus currently supports Google for these connections: Gmail, Google Calendar, and Google Drive. Connect Google supplies shared authorization used by the service-owned setups. Google authorization is backed by a Google Cloud project whose OAuth configuration makes the requested permissions explicit. Setup uses the downloaded JSON file for a Desktop OAuth client.
There are two routes to that client:
- The Famulus developer maintains an experimental Google Cloud project. An
OAuth project in Testing mode permits at most 100 manually listed test
users, and their refresh tokens expire after seven days, so they must
authorize again. If the developer has personally added your Google account
and provided the Desktop OAuth client JSON, give
connect-googlethe local path to that file when asked. - Otherwise,
connect-googleguides you through creating a Google Cloud project and Desktop OAuth client. Download that project's JSON and give the skill its local path instead.
The JSON contains a client secret. It must remain local: do not paste its contents into a model session, commit it to a repository, or attach it to an issue. The OAuth client identifies the application but grants no account access until you complete Google's authorization flow. Review the security and privacy boundary before granting access.
3. Schedule recurring skill runs
3.1 Set up and test the job
The recurring-tasks skill turns an already configured skill workflow into a
repeated job. Typical uses include triaging email and preparing a daily plan.
Configure and test the underlying skill interactively before enabling its
recurring job.
The Automation Quickstart explains the unattended execution boundary and the normal setup and verification sequence.
3.2 Diagnose platform problems
Recurring scheduling is implemented for Linux, macOS, and Windows, but it has been tested most thoroughly on Linux. Platform-specific scheduler setup, triggering, and health checks may therefore be less polished on macOS and Windows.
If a recurring job fails, preserve the exact error and ask the assistant to
diagnose and repair it. Also ask the assistant to use send-feedback so that
the developer can learn from the failure. That skill prepares a redacted report
and sends it only after you review and approve the complete message.