Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ later without renumbering anything.
| `VERSIONS.md` | The verified dependency versions, generated from `lib/trinity/versions.ex` |
| `CLAUDE.md` | The engineering contract: slice rules, definition of done, proof standard |
| `docs/` | Vision, architecture, tech stack, conventions, slice process, data model, risks, security model, standards; packaging, the FIPS leg, backup and restore, performance measurements |
| `slices/059-mcp-library-spike/FINDINGS.md` | What the MCP server core (`beam_mcp`) ships, carries, refuses or leaves open against the 2026-07-28 checklist; the reference for the MCP phase |
| `docs/adr/` | Architecture decision records. One is added whenever a decision changes |
| `slices/` | One folder per slice: specification, notes and proof |
| `templates/` | The templates a new slice, proof or decision record starts from |
Expand Down Expand Up @@ -175,11 +176,12 @@ every project space.
## Related projects

[beam_mcp](https://github.com/ScriptKittyOS/beam_mcp) is a Model Context Protocol server core for
the BEAM from the same organisation, on Hex as `beam_mcp`. Trinity does not depend on it today.
Trinity's MCP layer (milestone M5a) is chosen by measurement in slice 059, where beam_mcp is one
of the candidates for the server side; the client side and the authorization server are Trinity's
own work whichever library is chosen. `docs/adr/0007-mcp-2026-07-28-target-and-library.md`
records the protocol target and how the choice is made.
the BEAM from the same organisation, on Hex as `beam_mcp`. Trinity depends on it since slice 059,
pinned at 0.8.0 and reached only through the `Trinity.MCP` boundary; slice 059's `FINDINGS.md`
measures what it ships against the 2026-07-28 checklist, and the MCP phase (milestone M5a) builds
Trinity's client driver, the approval loop and authorization above it. The client side and the
authorization server are Trinity's own work. `docs/adr/0007-mcp-2026-07-28-target-and-library.md`
records the protocol target and the layering.

## License

Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ standards register names the rows that ask for them.
| 040 | Skills registry + agentskills.io format + progressive disclosure | 4 Skills | M | 020 | approved |
| 041 | Skill self-management with staged approval + scanner | 4 Skills | M | 040, 021 | approved |
| 050 | Scheduler: Oban cron agent tasks with delivery targets | 5 Automation | M | 012 | planned |
| 059 | MCP capability gap against beam_mcp, and the server seam probe | 6 MCP | S/M | 020 | planned |
| 059 | MCP capability gap against beam_mcp, and the server seam probe | 6 MCP | S/M | 020 | done |
| 060 | MCP client: Trinity's thin driver (2026-07-28 preferred, 2025-11-25 compat, MRTR, Tasks) | 6 MCP | L | 059, 021 | planned |
| 061 | MCP server (stateless 2026-07-28 + compat, MRTR approvals, headless profile) | 6 MCP | M | 060, 024 | planned |
| 062 | MCP authorization: OAuth client role, RS, embedded AS, Enterprise Managed Authorization (ID-JAG) | 6 MCP | L | 061 | planned |
Expand Down
2 changes: 1 addition & 1 deletion VERSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ never pin a version hex marks as retired or vulnerable.
| `oban` | ~> 2.24 | 🔍 not yet a dependency | Uses `Oban.Engines.Lite` on SQLite. ⚠️ Oban Pro Workflows/Smart engine are Postgres-only. Added at Slice 050. |
| `req` | ~> 0.5 | ✅ in `mix.lock` | HTTP client. |
| `req_llm` | ~> 1.22 | ✅ in `mix.lock` | Provider layer (streaming, tools, structured output, usage). ⚠️ The pin was `~> 1.10` against a recorded latest of 1.10.0; the real latest was twelve minors ahead. Check event shapes against the current version at Slice 011, not against this file's prose. Added at Slice 011. |
| `beam_mcp` | ~> 0.8 | 🔍 not yet a dependency | MCP server core, Apache-2.0, ADR-0007 decision 5 (owner decision 2026-09-08, recorded 2026-09-20). 0.8.0 on hex.pm, standing before 1.0.0. Server side only: the client, MRTR and OAuth are Trinity's, above it. Added at Slice 059. The earlier candidate list (anubis_mcp, fastest_mcp, gen_mcp) is history. |
| `beam_mcp` | ~> 0.8 | ✅ in `mix.lock` | MCP server core, Apache-2.0, ADR-0007 decision 5 (owner decision 2026-09-08, recorded 2026-09-20). 0.8.0 on hex.pm, standing before 1.0.0. Server side only: the client, MRTR and OAuth are Trinity's, above it. Added at Slice 059. The earlier candidate list (anubis_mcp, fastest_mcp, gen_mcp) is history. |
| `jido` | not used (ADR-0009, decided 2026-09-20) | 🔍 not a single package | Measured at the Slice 012 checkpoint and not adopted: the agent runtime duplicates PubSub, Oban and the gateways and adds a second tool executor; the action shape is written in-tree at Slice 020 with `jsv` for its schemas. The row stays so the decision is visible where a reader would look for the package. |
| `jason` | ~> 1.2 | ✅ in `mix.lock` | |
| `boundary` | ~> 0.10 | ✅ in `mix.lock` | Compile-time module dependency enforcement. Measured at Slice 000: it compiles and enforces on Elixir 1.20.4 / OTP 28, and it reports violations as **warnings**, so it enforces only while `--warnings-as-errors` is on the compile step. ⚠️ No release since 2024-09-25. |
Expand Down
1 change: 1 addition & 0 deletions coverage.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ slice_id percent sha date
032 78.99 193800e 2026-09-21
040 79.86 dc9dc6b 2026-09-21
041 80.55 ae200d7 2026-09-21
059 80.54 53c9091 2026-09-21
2 changes: 1 addition & 1 deletion docs/01-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ without anything failing.
| `Trinity.Memory` | Always-on tiers with their budget and consolidator (030), search (031), semantic store and retrieval (032), compaction (023) | LLM (summaries/embeddings), Repo |
| `Trinity.Skills` | SKILL.md parsing, registry, loader, manager, scanner (as built at 040: parser, sources, registry, index, the three tools; at 041: staging, promotion, manager, scanner, diff, learn, `skill_manage` and `learn`) | Repo, Permissions, **Effects**, **Receipts**, Sandbox (as built at 041: Tools, Memory, Permissions, Receipts and LLM; Effects is not a dependency: the promotion is not a tool call, it writes its own effect receipt; Tools never depends on Skills) |
| `Trinity.Scheduler` | Oban workers for agent tasks, delivery | Sessions, Gateways, **Repo** |
| `Trinity.MCP` | Client manager, tool bridge, server | Tools, **Effects**, **Permissions**, Memory |
| `Trinity.MCP` | Client manager, tool bridge, server (as built at 059: the boundary alone, holding the core's version, its JSON depth and its telemetry event names) | Tools, **Effects**, **Permissions**, Memory (as built at 059: a top-level boundary, like `Trinity.Smoke`, with `deps: [Trinity, BeamMCP.JSON]`; the boundary compiler checks every call into the `beam_mcp` application and this boundary alone lists its modules) |
| `Trinity.Gateways` | Adapter behaviour, router, allowlists, pairing | Sessions, **Permissions**, PubSub |
| `Trinity.Subagents` | Delegation, result collection | Sessions, Tools |
| `Trinity.Sandbox` | Luerl runners, resource limits | none |
Expand Down
38 changes: 38 additions & 0 deletions lib/trinity/mcp.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# SPDX-FileCopyrightText: Sudo Apt Holdings LLC
# SPDX-License-Identifier: Apache-2.0
defmodule Trinity.MCP do
@moduledoc """
The MCP boundary (slice 059, ADR-0007 decisions 4 and 5): the one place in Trinity that may
import `BeamMCP`. The boundary compiler checks every call into the `beam_mcp` application
(`boundary: [default: [check: [apps: [:beam_mcp]]]]` in mix.exs), and this boundary alone
lists `BeamMCP.*` modules among its deps, so a `BeamMCP.*` reference anywhere else is a
compile error under `--warnings-as-errors`. Slice 060 puts the client driver here
(`Trinity.MCP.Client`), 061 the server (`Trinity.MCP.Server`); at 059 the boundary holds the
facts the FINDINGS table measured and nothing that serves.
"""
# beam_mcp defines no boundaries and no `BeamMCP` root module, so each of its modules this
# boundary reaches is named as its own implicit boundary (the boundary library's rule for
# external apps); 060 and 061 extend the list as they reach more of the core.
#
# A top-level boundary (as `Trinity.Smoke` is), not a sub-boundary of `Trinity`: the
# library lets a nested boundary depend on an external module only when an ancestor does,
# and `Trinity` must never list `BeamMCP` (that would open the core to it).
use Boundary, top_level?: true, deps: [Trinity, BeamMCP.JSON], exports: []

@doc "The core's version, from its application spec."
@spec core_version() :: String.t()
def core_version, do: to_string(Application.spec(:beam_mcp, :vsn))

@doc "The JSON nesting depth the core's decoder accepts: the first fact 060's driver builds on."
@spec json_max_depth() :: pos_integer()
def json_max_depth, do: BeamMCP.JSON.max_depth()

@doc "The core's telemetry events (`[:beam_mcp, :dispatch, :start | :stop | :exception]`), for slice 090's catalogue."
@spec core_events() :: [[atom()]]
def core_events,
do: [
[:beam_mcp, :dispatch, :start],
[:beam_mcp, :dispatch, :stop],
[:beam_mcp, :dispatch, :exception]
]
end
6 changes: 6 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ defmodule Trinity.MixProject do
# 90. `mix test --cover` was still exiting 3 on a rule this project does not have, and
# the comment above it claimed otherwise for the whole of slice 000.
test_coverage: [summary: [threshold: 0]],
# Slice 059: calls into beam_mcp are checked by the boundary compiler everywhere;
# only Trinity.MCP lists BeamMCP among its deps (ADR-0007 decision 4 and 5).
boundary: [default: [check: [apps: [:beam_mcp]]]],
releases: releases()
]
end
Expand Down Expand Up @@ -157,6 +160,9 @@ defmodule Trinity.MixProject do
# (Trinity.Skills.Watcher); both were in the lock already as transitive dependencies.
{:yaml_elixir, "~> 2.12"},
{:file_system, "~> 1.1"},
# Slice 059: the MCP server core (ADR-0007 decision 5), reached only through the
# Trinity.MCP boundary; the slice measures its gap, 060 and 061 build on it.
{:beam_mcp, "~> 0.8"},
# Slice 013 (owner decision, 2026-09-20): the linux package builds mdex's NIF from
# source for musl (MDEX_NATIVE_BUILD=1 and TRINITY_NIF_TARGET in config/config.exs),
# because neither precompiled artifact loads in Burrito's musl ERTS (NOTES finding 13).
Expand Down
1 change: 1 addition & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"abnf_parsec": {:hex, :abnf_parsec, "2.1.0", "c4e88d5d089f1698297c0daced12be1fb404e6e577ecf261313ebba5477941f9", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e0ed6290c7cc7e5020c006d1003520390c9bdd20f7c3f776bd49bfe3c5cd362a"},
"axon": {:hex, :axon, "0.8.1", "c4a975e62a14ab6c374997b77367ec3a4c2740952ac474d3b0f202c91b7f75c4", [:mix], [{:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}, {:kino_vega_lite, "~> 0.1.7", [hex: :kino_vega_lite, repo: "hexpm", optional: true]}, {:nx, "~> 0.10", [hex: :nx, repo: "hexpm", optional: false]}, {:polaris, "~> 0.1", [hex: :polaris, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1 or ~> 4.1", [hex: :table_rex, repo: "hexpm", optional: true]}], "hexpm", "682a3517489300507ac9345f28341e7fa95bc5b4960d645816074ce551795d37"},
"bandit": {:hex, :bandit, "1.12.5", "af205a8e550f304caae09a97d29fd3c79a7f337526ea7cd772d2ff11d2f7c800", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.5", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "c5684ca062fa407cac115aec3256383f3e2ec9fdced7904d59cf5a7bb7ed6181"},
"beam_mcp": {:hex, :beam_mcp, "0.8.0", "49f2607a92da4137cd1d11fc8669c396e1d93eedf7a3e29aaab1531dd41bd9c2", [:mix], [{:bandit, "~> 1.5", [hex: :bandit, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:plug, "~> 1.16", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b5a1beba2c936c2c50e164c43240ac31bc8b159a994980083ec0f6562392801e"},
"boundary": {:hex, :boundary, "0.10.4", "5fec5d2736c12f9bfe1720c3a2bd8c48c3547c24d6002ebf8e087570afd5bd2f", [:mix], [], "hexpm", "8baf6f23987afdb1483033ed0bde75c9c703613c22ed58d5f23bf948f203247c"},
"bumblebee": {:hex, :bumblebee, "0.7.1", "0d6a757f955671a379ebcf4ed07565513fa767b1869169b989f65ba7958a80f4", [:mix], [{:axon, "~> 0.8.0", [hex: :axon, repo: "hexpm", optional: false]}, {:jason, "~> 1.4.0", [hex: :jason, repo: "hexpm", optional: false]}, {:nx, "~> 0.12.0 or ~> 0.13.0", [hex: :nx, repo: "hexpm", optional: false]}, {:nx_image, "~> 0.1.0", [hex: :nx_image, repo: "hexpm", optional: false]}, {:nx_signal, "~> 0.2.0", [hex: :nx_signal, repo: "hexpm", optional: false]}, {:safetensors, "~> 0.1.3", [hex: :safetensors, repo: "hexpm", optional: false]}, {:tokenizers, "~> 0.4", [hex: :tokenizers, repo: "hexpm", optional: false]}, {:unpickler, "~> 0.1.0", [hex: :unpickler, repo: "hexpm", optional: false]}, {:unzip, "~> 0.12.0 or ~> 0.13.0", [hex: :unzip, repo: "hexpm", optional: false]}], "hexpm", "f26b3355700e3c7580014d41ce477d87d9fd71a60b76d5b64701dacb07830a58"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
Expand Down
Loading
Loading