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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
15 changes: 5 additions & 10 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,7 @@ The full policy is canonical in `hyperpolymath/standards`. Key points relevant t

### TypeScript Exemptions (Approved)

The "no new TypeScript" rule has 6 approved exemptions in this repo — all MCP cartridge adapters. The MCP SDK (`@anthropic/sdk`) is TypeScript-native, and the adapters are JSON-RPC-over-stdio glue. Until AffineScript has bindings to the MCP protocol, these adapters must remain TS.

| Path | Files | Rationale | Unblock condition |
|---|---|---|---|
| `cartridges/{academic-workflow,bofig,ephapax,fireflag,hesiod,sanctify}-mcp/adapter/mod.ts` | 6 | MCP cartridge adapters using `@anthropic/sdk`. The SDK is TS-native; equivalent functionality requires AffineScript bindings to MCP, which don't exist yet. | AffineScript MCP bindings (no scheduled issue — file under `affinescript` when scope is decided). |

Adding to this list requires explicit user approval and an unblock condition. Audit lineage: TS-elimination audit, 2026-05-02. Mirror tables in `affinescript`, `standards`, and `my-lang` repos.
The former 6 exemptions (MCP cartridge adapters under `cartridges/*/adapter/mod.ts`) left this repo with the bundled `cartridges/` tree — the cartridges and their adapter exemptions now live in `boj-server-cartridges` (see its CLAUDE.md exemption table). No TS exemptions remain in this repo; adding one requires explicit user approval and an unblock condition. Audit lineage: TS-elimination audit, 2026-05-02.

### Documentation Format

Expand All @@ -47,9 +41,10 @@ exceptions:

### The "unified adapter"

The current canonical shape (see `cartridges/k9iser-mcp/adapter/` for the
reference implementation, or `cartridges/templates/gossamer-mcp/adapter/` in
`boj-server-cartridges` for the minting template): **one loopback listener**,
The current canonical shape (see
`cartridges/domains/config/k9iser-mcp/adapter/` in `boj-server-cartridges` for
the reference implementation, or `cartridges/templates/gossamer-mcp/adapter/`
there for the minting template): **one loopback listener**,
protocol-classified (REST `/invoke`, SSE `/sse`, GraphQL `/graphql`, gRPC-compat
`/grpc/<Svc>/<Method>`), that funnels every request through a **transaction
gate** (`exposureSatisfied`, mirroring the cartridge's own Idris2 exposure
Expand Down
20 changes: 8 additions & 12 deletions .github/workflows/abi-drift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,14 @@ jobs:
BASE: ${{ github.base_ref }}
BEFORE: ${{ github.event.before }}
run: |
set -uo pipefail
run=true
if [ "$EVENT" = pull_request ]; then
git fetch --no-tags --depth=200 origin "$BASE" 2>/dev/null \
&& changed=$(git diff --name-only "origin/${BASE}...HEAD" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^cartridges/.*/abi/|^cartridges/.*/ffi/' && run=true || run=false; }
elif [ "$EVENT" = push ] && [ -n "$BEFORE" ] && [ "$BEFORE" != 0000000000000000000000000000000000000000 ]; then
changed=$(git diff --name-only "${BEFORE}...${GITHUB_SHA}" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^cartridges/.*/abi/|^cartridges/.*/ffi/' && run=true || run=false; }
fi
printf 'run=%s\n' "$run" >> "$GITHUB_OUTPUT"
echo "relevant=$run; changed files:"; printf '%s\n' "${changed:-<none computed>}"
# RETIRED GATE: the bundled cartridges/ tree (this gate's entire
# subject — per-cartridge Safe*.idr ↔ *_ffi.zig drift) moved to
# hyperpolymath/boj-server-cartridges. run=false keeps the required
# check satisfied (skipped jobs report success) without phantom
# contexts; port the iseriser gate to the cartridges repo before
# deleting this workflow + its required context.
printf 'run=false\n' >> "$GITHUB_OUTPUT"
echo "relevant=false; bundled cartridges retired — nothing to verify here"

verify:
name: Emit manifest + verify FFI
Expand Down
17 changes: 8 additions & 9 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ jobs:
if [ "$EVENT" = pull_request ]; then
git fetch --no-tags --depth=200 origin "$BASE" 2>/dev/null \
&& changed=$(git diff --name-only "origin/${BASE}...HEAD" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^adapter/|^cartridges/|^ffi/|^mcp-bridge/|^tests/|^src/' && run=true || run=false; }
&& { printf '%s\n' "$changed" | grep -qE '^adapter/|^ffi/|^mcp-bridge/|^tests/|^src/' && run=true || run=false; }
elif [ "$EVENT" = push ] && [ -n "$BEFORE" ] && [ "$BEFORE" != 0000000000000000000000000000000000000000 ]; then
changed=$(git diff --name-only "${BEFORE}...${GITHUB_SHA}" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^adapter/|^cartridges/|^ffi/|^mcp-bridge/|^tests/|^src/' && run=true || run=false; }
&& { printf '%s\n' "$changed" | grep -qE '^adapter/|^ffi/|^mcp-bridge/|^tests/|^src/' && run=true || run=false; }
fi
printf 'run=%s\n' "$run" >> "$GITHUB_OUTPUT"
echo "relevant=$run; changed files:"; printf '%s\n' "${changed:-<none computed>}"
Expand Down Expand Up @@ -100,14 +100,13 @@ jobs:

- name: Build FFI libraries
run: |
# Subshell keeps the cd contained so the cartridge loop below runs
# from the repo root (otherwise its glob never matches). `zig build
# invoke` builds the boj-invoke CLI the Elixir Invoker shells out to
# for tool dispatch — without it every FFI invoke returns {} (cli_missing).
# `zig build invoke` builds the boj-invoke CLI the Elixir Invoker
# shells out to for tool dispatch — without it every FFI invoke
# returns {} (cli_missing). The fixture catalog's feedback-mcp is
# the one cartridge the E2E invokes end-to-end (bundled cartridges/
# was retired; see hyperpolymath/boj-server-cartridges).
(cd ffi/zig && zig build && zig build invoke)
for cart in cartridges/*/ffi; do
if [ -f "$cart/build.zig" ]; then (cd "$cart" && zig build) || true; fi
done
(cd tests/fixtures/cartridges/feedback-mcp/ffi && zig build)

- name: Run E2E full test suite
run: bash tests/e2e_full.sh
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ on:
branches: [main]
paths:
- 'ffi/**'
- 'cartridges/**/ffi/**'
- 'mcp-bridge/**'
schedule:
- cron: '0 3 * * 3' # Weekly on Wednesday
Expand Down
21 changes: 9 additions & 12 deletions .github/workflows/lsp-dap-bsp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,15 @@ jobs:
BASE: ${{ github.base_ref }}
BEFORE: ${{ github.event.before }}
run: |
set -uo pipefail
run=true
if [ "$EVENT" = pull_request ]; then
git fetch --no-tags --depth=200 origin "$BASE" 2>/dev/null \
&& changed=$(git diff --name-only "origin/${BASE}...HEAD" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^cartridges/(lsp|dap|bsp)-mcp/|^src/abi/Boj/Protocol\.idr$' && run=true || run=false; }
elif [ "$EVENT" = push ] && [ -n "$BEFORE" ] && [ "$BEFORE" != 0000000000000000000000000000000000000000 ]; then
changed=$(git diff --name-only "${BEFORE}...${GITHUB_SHA}" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^cartridges/(lsp|dap|bsp)-mcp/|^src/abi/Boj/Protocol\.idr$' && run=true || run=false; }
fi
printf 'run=%s\n' "$run" >> "$GITHUB_OUTPUT"
echo "relevant=$run; changed files:"; printf '%s\n' "${changed:-<none computed>}"
# RETIRED GATE: the lsp/dap/bsp cartridges this workflow built and
# conformance-tested moved to hyperpolymath/boj-server-cartridges
# with the rest of the bundled cartridges/ tree. Protocol.idr's
# typecheck is covered by the Proofs Gate (src/abi). run=false keeps
# the required check satisfied (skipped jobs report success); port
# the conformance jobs to the cartridges repo before deleting this
# workflow + its required context.
printf 'run=false\n' >> "$GITHUB_OUTPUT"
echo "relevant=false; bundled cartridges retired — nothing to verify here"

abi-check:
name: ABI Specification Check (Idris2)
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/proofs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ jobs:
if [ "$EVENT" = pull_request ]; then
git fetch --no-tags --depth=200 origin "$BASE" 2>/dev/null \
&& changed=$(git diff --name-only "origin/${BASE}...HEAD" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^src/abi/|^cartridges/.*/abi/|^verification/|^scripts/check-trusted-base\.sh$|^scripts/typecheck-proofs\.sh$|^\.tool-versions$' && run=true || run=false; }
&& { printf '%s\n' "$changed" | grep -qE '^src/abi/|^verification/|^scripts/check-trusted-base\.sh$|^scripts/typecheck-proofs\.sh$|^\.tool-versions$' && run=true || run=false; }
elif [ "$EVENT" = push ] && [ -n "$BEFORE" ] && [ "$BEFORE" != 0000000000000000000000000000000000000000 ]; then
changed=$(git diff --name-only "${BEFORE}...${GITHUB_SHA}" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^src/abi/|^cartridges/.*/abi/|^verification/|^scripts/check-trusted-base\.sh$|^scripts/typecheck-proofs\.sh$|^\.tool-versions$' && run=true || run=false; }
&& { printf '%s\n' "$changed" | grep -qE '^src/abi/|^verification/|^scripts/check-trusted-base\.sh$|^scripts/typecheck-proofs\.sh$|^\.tool-versions$' && run=true || run=false; }
fi
printf 'run=%s\n' "$run" >> "$GITHUB_OUTPUT"
echo "relevant=$run; changed files:"; printf '%s\n' "${changed:-<none computed>}"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/truthfulness.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ jobs:
if [ "$EVENT" = pull_request ]; then
git fetch --no-tags --depth=200 origin "$BASE" 2>/dev/null \
&& changed=$(git diff --name-only "origin/${BASE}...HEAD" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^cartridges/.*/cartridge\.json$|^cartridges/.*/ffi/|^ffi/|^elixir/lib/boj_rest/router\.ex$|^tests/truthfulness_check\.sh$' && run=true || run=false; }
&& { printf '%s\n' "$changed" | grep -qE '^ffi/|^elixir/lib/boj_rest/router\.ex$|^tests/truthfulness_check\.sh$' && run=true || run=false; }
elif [ "$EVENT" = push ] && [ -n "$BEFORE" ] && [ "$BEFORE" != 0000000000000000000000000000000000000000 ]; then
changed=$(git diff --name-only "${BEFORE}...${GITHUB_SHA}" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^cartridges/.*/cartridge\.json$|^cartridges/.*/ffi/|^ffi/|^elixir/lib/boj_rest/router\.ex$|^tests/truthfulness_check\.sh$' && run=true || run=false; }
&& { printf '%s\n' "$changed" | grep -qE '^ffi/|^elixir/lib/boj_rest/router\.ex$|^tests/truthfulness_check\.sh$' && run=true || run=false; }
fi
printf 'run=%s\n' "$run" >> "$GITHUB_OUTPUT"
echo "relevant=$run; changed files:"; printf '%s\n' "${changed:-<none computed>}"
Expand Down
94 changes: 5 additions & 89 deletions .github/workflows/zig-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ jobs:
if [ "$EVENT" = pull_request ]; then
git fetch --no-tags --depth=200 origin "$BASE" 2>/dev/null \
&& changed=$(git diff --name-only "origin/${BASE}...HEAD" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^ffi/|^cartridges/.*/ffi/' && run=true || run=false; }
&& { printf '%s\n' "$changed" | grep -qE '^ffi/' && run=true || run=false; }
elif [ "$EVENT" = push ] && [ -n "$BEFORE" ] && [ "$BEFORE" != 0000000000000000000000000000000000000000 ]; then
changed=$(git diff --name-only "${BEFORE}...${GITHUB_SHA}" 2>/dev/null) \
&& { printf '%s\n' "$changed" | grep -qE '^ffi/|^cartridges/.*/ffi/' && run=true || run=false; }
&& { printf '%s\n' "$changed" | grep -qE '^ffi/' && run=true || run=false; }
fi
printf 'run=%s\n' "$run" >> "$GITHUB_OUTPUT"
echo "relevant=$run; changed files:"; printf '%s\n' "${changed:-<none computed>}"
Expand All @@ -63,105 +63,21 @@ jobs:
timeout-minutes: 30
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
# Needed so `git diff origin/<base>...HEAD` can identify the
# cartridges actually changed in this PR. Full history is cheap
# on this repo; cuts down on cross-cartridge false-positive
# gating where a PR is blocked by pre-existing breakage in
# unrelated cartridges (browser-mcp, orchestrator-lsp-mcp,
# etc.). On push/main we keep the full per-cartridge sweep.
fetch-depth: 0

- name: Install Zig
uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2
with:
version: 0.15.2

- name: Determine cartridges to test
id: scope
env:
EVENT: ${{ github.event_name }}
BASE_REF: ${{ github.base_ref }}
run: |
set -euo pipefail
all="$(ls -d cartridges/*/ffi/ 2>/dev/null | sed 's|cartridges/||;s|/ffi/||' | sort)"
if [ "$EVENT" = "pull_request" ]; then
git fetch --no-tags --depth=50 origin "$BASE_REF" || true
# Only scope cartridges whose `ffi/` actually changed —
# `cartridge.json` edits (e.g. adding a status field) and
# `abi/` edits should not pull a cart into this FFI test
# job, which exists to validate Zig builds. Using
# `cartridges/*/ffi/**` as the pathspec ensures only
# ffi-relevant diffs count (also matches the workflow's
# own `on.paths` filter — they were inconsistent before).
changed="$(git diff --name-only "origin/${BASE_REF}...HEAD" -- 'cartridges/*/ffi/**' \
| awk -F/ '{print $2}' | sort -u)"
scope=""
while IFS= read -r cart; do
[ -z "$cart" ] && continue
if printf '%s\n' "$changed" | grep -qx "$cart"; then
scope="$scope$cart"$'\n'
fi
done <<< "$all"
else
scope="$all"
fi
{
echo 'carts<<EOF'
printf '%s' "$scope"
echo
echo 'EOF'
} >> "$GITHUB_OUTPUT"
echo "Cartridges in scope for this run:"
printf ' • %s\n' $(printf '%s\n' "$scope" | grep -v '^$' || true)

# Bundled cartridges/ was retired; per-cartridge FFI builds are gated
# in hyperpolymath/boj-server-cartridges. This workflow now covers the
# core FFI tree (ffi/zig) only.
- name: Run catalogue tests
run: cd ffi/zig && zig build test --summary all

- name: Run readiness tests
run: cd ffi/zig && zig build readiness --summary all

- name: Run cartridge FFI tests
env:
CARTS: ${{ steps.scope.outputs.carts }}
run: |
if [ -z "$(printf '%s' "$CARTS" | tr -d '[:space:]')" ]; then
echo "::notice::No cartridges changed in this PR — skipping per-cartridge FFI tests."
exit 0
fi
failed=""
while IFS= read -r cart; do
[ -z "$cart" ] && continue
echo "::group::Testing $cart..."
if cd "cartridges/$cart/ffi" && zig build test --summary all 2>&1; then
echo " ✓ $cart passed"
else
echo " ✗ $cart FAILED"
failed="$failed $cart"
fi
cd "$GITHUB_WORKSPACE"
echo "::endgroup::"
done <<< "$CARTS"
if [ -n "$failed" ]; then
echo "::error::Failed cartridges:$failed"
exit 1
fi

- name: Build cartridge shared libraries
env:
CARTS: ${{ steps.scope.outputs.carts }}
run: |
if [ -z "$(printf '%s' "$CARTS" | tr -d '[:space:]')" ]; then
echo "::notice::No cartridges changed in this PR — skipping per-cartridge .so build."
exit 0
fi
while IFS= read -r cart; do
[ -z "$cart" ] && continue
echo "Building $cart .so..."
cd "cartridges/$cart/ffi" && zig build
cd "$GITHUB_WORKSPACE"
done <<< "$CARTS"

- name: Build static library
run: cd ffi/zig && zig build lib

Expand Down
20 changes: 6 additions & 14 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ build-release *args:

# Build and watch for changes (requires entr)
build-watch:
find ffi/ cartridges/ -name '*.zig' | entr -c just build
find ffi/ -name '*.zig' | entr -c just build

# Clean build artifacts [reversible: rebuild with `just build`]
clean:
Expand Down Expand Up @@ -378,12 +378,12 @@ fix: fmt
# Format all source files [reversible: git checkout]
fmt:
@echo "Zig format..."
find ffi/ cartridges/ -name '*.zig' -exec zig fmt {} +
find ffi/ -name '*.zig' -exec zig fmt {} +

# Check formatting without changes
fmt-check:
@echo "Checking Zig formatting..."
find ffi/ cartridges/ -name '*.zig' -exec zig fmt --check {} +
find ffi/ -name '*.zig' -exec zig fmt --check {} +

# Lint — verify zero believe_me + type-check all ABI files
lint: verify-no-believe-me typecheck
Expand Down Expand Up @@ -423,16 +423,8 @@ matrix:
echo " BoJ Capability Matrix"
echo "═══════════════════════════════════════════════════"
echo ""
echo " Cartridge ABI FFI Adapter Tests"
echo " ───────────────────────────────────────────────"
for cart in database-mcp fleet-mcp nesy-mcp agent-mcp; do
ABI="✗"; FFI="✗"; ADAPTER="✗"; TESTS="✗"
[ -f "cartridges/$cart/abi"/*/*.idr ] 2>/dev/null && ABI="✓"
[ -f "cartridges/$cart/ffi"/*_ffi.zig ] 2>/dev/null && FFI="✓"
[ -d "elixir" ] 2>/dev/null && ADAPTER="✓"
[ -f "cartridges/$cart/ffi/build.zig" ] 2>/dev/null && TESTS="✓"
printf " %-20s %s %s %s %s\n" "$cart" "$ABI" "$FFI" "$ADAPTER" "$TESTS"
done
echo " Cartridge sources: hyperpolymath/boj-server-cartridges (canonical registry)"
echo " Local cache: \${BOJ_CARTRIDGES_PATH:-\$HOME/.boj/cartridges} (populate via scripts/fetch-cartridges.sh)"
echo ""
echo " Core catalogue: ffi/zig/src/catalogue.zig"
echo " Dynamic loader: ffi/zig/src/loader.zig"
Expand Down Expand Up @@ -1364,7 +1356,7 @@ tour:
echo " Federation.idr Umoja gossip protocol"
echo ""
echo "Key directories:"
echo " cartridges/ 70+ cartridge directories"
echo " (cartridges now live in hyperpolymath/boj-server-cartridges)"
echo " ffi/zig/ Core catalogue FFI"
echo " elixir/ REST server (Plug/Cowboy)"
echo " container/ Stapeln container ecosystem"
Expand Down
Loading
Loading