SEIF and Trinity
Trinity (Ability AI, Apache 2.0) runs a company's agents: each one is Claude Code, Codex or Gemini CLI in its own container over its own git repository, with a scheduler, approvals before irreversible skills, guardrail hooks, an audit ledger and Slack, Telegram, WhatsApp (Twilio) and voice channels. What an agent knows is left to the agent: "Agents manage their own memory. Trinity provides storage, not strategy." (docs/TRINITY_COMPATIBLE_AGENT_GUIDE.md, Memory Management).
SEIF is that strategy: what each agent receives for a task, from which source, what stays out and why, proven by tests that run without a model. The two complement each other: Trinity operates the agent, SEIF decides and proves what it knows.
The whole team
Publicar no Trinity → O time inteiro sends every member as its own Trinity agent, the team's routines as schedules and its flows as permissions; see One project, any runtime.
One SEIF agent as a Trinity agent
seif export --target trinity --agent closer --project <repo> [--output dir] # bundled (SEIF sees nothing)
seif export --target trinity --agent closer --mcp-url https://…/<handle>/<slug>/mcp # hosted
or, on the web, Contexto → Conectar a um agente → Trinity → Publicar no Trinity (or baixar o agente (.zip)). The repository (runtime/engine/trinity-export.mjs, format seif.trinity-agent.v1) has three modes:
| Mode | When | What SEIF sees |
|---|---|---|
hosted | the project's MCP address is public https | every call (Contexto → Interações) |
bridge | SEIF is reachable by Trinity but not at a public https address (local Docker, LAN, VPN). Trinity's validator refuses http and private addresses for HTTP MCP servers and allows node <script> as stdio, so seif/mcp-bridge.mjs (node builtins only) forwards each JSON-RPC message to SEIF | every call |
bundled | the context server is off | nothing: the engine and the agent's context travel inside it |
Publishing from SEIF mints one agent token per Trinity agent (web/mcp-link.mjs → mcp_clients: its own profile, named in every interaction, revoked alone under Tokens dos agentes) and passes it to Trinity at deploy time (deploy-local → credentials: { SEIF_MCP_TOKEN, SEIF_MCP_URL }), so Trinity's startup renders .mcp.json.template with it. The person never copies a token. An agent token carries its agent's SEIF capabilities: without api, no connected-API tool is offered, and an external agent (one that talks to customers) never gets them, whichever token asks.
The publish form picks the environment the agents query: production (…/mcp, a release Build) or staging (…/staging/mcp, the draft). A staging publication gets its own agent names (…-staging) and tokens that work only on the staging server, so a team can be tried in Trinity next to the one in production; see Environments.
Always consult SEIF (the compass hook)
Each agent has a setting, Consultar o SEIF antes de responder (workspace.<agent>.compass in its AGENT.md):
| Setting | Trinity | SEIF's own chat and team | OpenBot, n8n, other MCP clients |
|---|---|---|---|
always (default) | .claude/settings.json registers UserPromptSubmit, Stop, StopFailure and a filtered PreToolUse hook in seif/compass-hook.mjs. In hosted/bridge mode, UserPromptSubmit opens a server-issued HTTP turn, calls POST …/context/compass with X-SEIF-Turn-Id, and atomically stores the active turn for the Claude session_id locally with mode 0600. prompt_id is retained only as opaque metadata when supplied; Stop reports completed; StopFailure reports failed. The script keeps a bounded, 0600 outbox for failed completion and pre-tool reports. PreToolUse records only the observed pre-execution intent and permitted identifiers for mcp__seif__.*, never tool input, an outcome, or a model answer. | SEIF resolves the context before every turn | told to call context_compass first, for every request |
when-needed | no hook; CLAUDE.md says to call context_compass before stating a business fact (a greeting needs none) | the same as always | told to call it before stating a business fact |
The hook never blocks a message: if the start or compass call fails, the prompt continues with an instruction that business facts are unconfirmed. A turn start, an HTTP context delivery and a pre-tool hook event are observed at their respective endpoints. completed and failed are reported technical runtime states. A missing endpoint receipt, MCP call, tool execution, result consumption, final response, customer-visible output and model comprehension are not observed. In particular, a hook tool_use_id is never treated as a correlation to a separately recorded SEIF MCP call without a secure runtime-provided link. Trinity keeps the file: it removes only a settings.json its own image shipped, and the hook has no env block and lives in the repository, so Trinity's commit guard accepts it.
| File | Why |
|---|---|
template.yaml | Trinity's metadata; declares SEIF_MCP_TOKEN (and SEIF_MCP_URL in bridge mode) as credentials |
CLAUDE.md | the agent's own instructions, then how to work from SEIF: context_compass before answering, context_report_gap when it cannot answer, never present stale facts as current, never show locators or check dates to the person answered (they are for verification and SEIF's audit trail), and what each SEIF capability becomes here |
.claude/skills/seif-context/SKILL.md | the same rule as a skill Trinity lists |
.mcp.json.template | hosted: type: http with Authorization: Bearer ${SEIF_MCP_TOKEN}; bridge: node /home/developer/seif/mcp-bridge.mjs with SEIF_MCP_URL/SEIF_MCP_TOKEN in env (the only place Trinity substitutes); bundled: node /home/developer/seif/engine.mjs mcp --project /home/developer/seif/context |
seif/mcp-bridge.mjs | bridge: the stdio → HTTP forwarder |
.claude/settings.json, seif/compass-hook.mjs | compass always: UserPromptSubmit creates a server-issued HTTP turn and obtains the compass answer; Stop / StopFailure report runtime completion; filtered PreToolUse emits bounded pre-execution intention only. The local state and bounded retry outbox are under ignored .tmp/seif-turns/, atomically written with 0600; neither contains prompts, tool input, model output or the agent token. |
seif/context/, seif/engine.mjs | bundled: the context repository as this agent sees it, and the single-file engine |
seif-trinity.json | the manifest: mode, observable, and capabilities (each SEIF capability as carried, native, pending with the step, or seif-only; runtime/engine/portability-report.mjs) |
.gitignore, .env.example, .trinity-manifest.json | what Trinity's compatibility checks require; the manifest lets Trinity verify the deploy (verified: true) |
Routines all travel as Trinity schedules: scheduled ones on their cron; event-triggered and manual ones disabled, with [PENDENTE · configurar após importar] in the description and message and the step that turns them on (a webhook on the schedule). The publish result lists every pending item.
Environments: production serves a release, staging the draft
The project's context server has one address per environment (web/mcp-link.mjs → mcp_environments):
| Environment | Address | Serves |
|---|---|---|
| production | <handle>/<slug>/mcp | the newest Build of release quality (all required tests pass), or the one the owner pinned |
| staging | <handle>/<slug>/staging/mcp | the working tree (the draft) |
| more staging environments the owner adds | <handle>/<slug>/<name>/mcp | the draft or one Build |
A Build of a project made of files keeps its authoring files (source.json, digest in context-build.json; never team/ records). The host writes them once into its own state (runtime/engine/build.mjs → materializeBuild, checked against the Build's design digest) and answers production from there, so what an owner edits reaches production only with the next Build that passes the tests. Gaps reported from production still land in the working tree, where they are fixed. A production with no such Build keeps answering from the draft, and says so in Contexto → Configuração, in Conectar and in every recorded call. An agent token belongs to one environment and is refused elsewhere (MCP_WRONG_ENVIRONMENT); the project's link token reaches every environment. A Build an environment pins cannot be deleted until that environment serves another.
What SEIF records (Context Flight Recorder)
Every call through the hosted MCP server or the normal HTTP context API (POST <handle>/<slug>/context/{compass,resolve,find,why,report-gap}) is kept in agent_interactions (web/mcp-recorder.mjs): caller (agent token, MCP client and version from initialize, user agent, session), profile, tool, question (personal data removed), verdict, what was received, what stayed out and why — sealed material included and marked not revealed to the agent —, the environment and what it served (a Build, or the draft), basis (design digest, distance to the latest Build), tests at the time, API operation and outcome (done, needs-approval, failed with the error), duration and the exact text the agent read. GAP and BLOCKED answers also land on the Gaps board. In Contexto → Interações an operator filters by agent or problem, replays a call against today's context (API effects are never replayed) and turns it into a Context Test (tests/interacoes/…: what it received must keep arriving, what was sealed must stay out).
For an application that must prove its own HTTP delivery sequence, use HTTP turn observation: the named client opens a server-issued turn, sends X-SEIF-Turn-Id on the context call, and reports technical completion. Claude Code exports with compass always add the hook receipts described above. An observed pre-tool event is only intent; completion is client-reported. These records do not prove that a model understood context, executed a tool, read a result or produced any customer-visible response.
A local Trinity
scripts/dev/trinity.sh fetches Trinity and installs it with its own scripts/deploy/start.sh, adding a machine-local docker-compose.override.yml that publishes the frontend (8095), the API (8000) and its MCP server (8080) on 0.0.0.0, so another computer of the tailnet opens it; Redis stays on 127.0.0.1. scripts/dev/web.sh runs SEIF's web product the same way (0.0.0.0:4390). Publish with SEIF's address as Trinity's containers reach it: http://host.docker.internal:4390.
Proof (2026-11-01, local Trinity on mini, bridge mode)
Missão CNH imported into the web host and published as a team to http://127.0.0.1:8000 with SEIF at http://host.docker.internal:4390: 5 agents verified: true, 11/11 routines as schedules (4 disabled and marked pending), 5 agent tokens. Asked through Trinity's chat API, the support agent (Claude Code 2.1.281) called context_compass before answering; SEIF recorded the call under Trinity · missao-cnh-team-support-…, with the partner commission sections sealed for it and not revealed to it. The same question to the guru resolved READY. A read on the partner API without the key stored was recorded as API_FAILED · SECRET_UNAVAILABLE.
Proof (2026-10-29, local Trinity v1.0 built from source)
The Missão CNH sales strategist (closer) exported bundled, deployed with POST /api/agents/deploy-local: verified: true, compatibility_hard_count: 0. Inside the agent container (agent-cnh-closer) the seif MCP server answered context_compass("vocês são do detran?") with knowledge/company/about.md#what-we-do in hand, no model called. The exported subset passes its own 14 tests (node seif/engine.mjs doctor --project seif/context); the market layer, outside the closer's profile, stayed home.