chore: merge origin/main — reconcile divergent branches

Integrates remote changes (session protocol, .custodian-brief.md, MCP
SSE/HTTP mode, workplan OPS-WP-0002 completion) with local changes
(AccessManagementDirective alignment, architecture docs, BRIDGE-WP-0004
and WARDEN-WP-0001 workplans).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-28 01:05:11 +00:00
7 changed files with 66 additions and 29 deletions

View File

@@ -4,7 +4,21 @@ State Hub: http://127.0.0.1:8000
### Session Protocol ### Session Protocol
**Step 0 — Tunnel health**
Before anything else:
```bash
bridge status
```
Bring up any stopped or stale tunnels before accessing remote services.
**Step 1 — Orient** **Step 1 — Orient**
Read the offline-safe brief first:
```bash
cat .custodian-brief.md
```
Then call the MCP tool for richer context (skip if unreachable):
``` ```
get_domain_summary("custodian") get_domain_summary("custodian")
``` ```

18
.custodian-brief.md Normal file
View File

@@ -0,0 +1,18 @@
<!-- custodian-brief: generated by fix-consistency — do not edit manually -->
# Custodian Brief — ops-bridge
**Domain:** (unknown)
**Last synced:** 2026-03-26 21:46 UTC
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
## Active Workstreams
*(none — repo may need first-session setup)*
---
## MCP Orientation (when available)
If the state-hub MCP server is reachable, call:
`get_domain_summary("")`
This provides richer cross-domain context.
If the MCP call fails, use this file as your orientation source.

View File

@@ -1,4 +1,4 @@
.PHONY: test lint install .PHONY: test lint install mcp-http mcp-stop
test: test:
uv run pytest uv run pytest
@@ -8,3 +8,9 @@ lint:
install: install:
uv tool install -e . uv tool install -e .
mcp-http: ## Start MCP server in SSE mode (default port 8002)
BRIDGE_MCP_PORT=$${BRIDGE_MCP_PORT:-8002} uv run python src/bridge/mcp_server/server.py --http
mcp-stop: ## Stop MCP server running on port 8002
@lsof -ti:$${BRIDGE_MCP_PORT:-8002} | xargs -r kill -TERM && echo "MCP server stopped" || echo "No MCP server running on port $${BRIDGE_MCP_PORT:-8002}"

View File

@@ -11,7 +11,7 @@ dependencies = [
"typer>=0.12", "typer>=0.12",
"pyyaml>=6.0", "pyyaml>=6.0",
"httpx>=0.27", "httpx>=0.27",
"fastmcp>=2.0.0", "fastmcp>=2.0.0,<3.1.0",
] ]
[project.scripts] [project.scripts]

View File

@@ -513,4 +513,13 @@ def resource_catalog_targets() -> str:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
if __name__ == "__main__": if __name__ == "__main__":
mcp.run(transport="stdio") import argparse
parser = argparse.ArgumentParser(description="OpsBridge MCP server")
parser.add_argument("--http", action="store_true", help="Run in SSE/HTTP mode instead of stdio")
args = parser.parse_args()
if args.http:
port = int(os.environ.get("BRIDGE_MCP_PORT", "8002"))
mcp.run(transport="sse", host="127.0.0.1", port=port)
else:
mcp.run(transport="stdio")

18
uv.lock generated
View File

@@ -345,7 +345,7 @@ wheels = [
[[package]] [[package]]
name = "fastmcp" name = "fastmcp"
version = "3.1.0" version = "3.0.2"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "authlib" }, { name = "authlib" },
@@ -365,14 +365,13 @@ dependencies = [
{ name = "python-dotenv" }, { name = "python-dotenv" },
{ name = "pyyaml" }, { name = "pyyaml" },
{ name = "rich" }, { name = "rich" },
{ name = "uncalled-for" },
{ name = "uvicorn" }, { name = "uvicorn" },
{ name = "watchfiles" }, { name = "watchfiles" },
{ name = "websockets" }, { name = "websockets" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/0a/70/862026c4589441f86ad3108f05bfb2f781c6b322ad60a982f40b303b47d7/fastmcp-3.1.0.tar.gz", hash = "sha256:e25264794c734b9977502a51466961eeecff92a0c2f3b49c40c070993628d6d0", size = 17347083 } sdist = { url = "https://files.pythonhosted.org/packages/11/6b/1a7ec89727797fb07ec0928e9070fa2f45e7b35718e1fe01633a34c35e45/fastmcp-3.0.2.tar.gz", hash = "sha256:6bd73b4a3bab773ee6932df5249dcbcd78ed18365ed0aeeb97bb42702a7198d7", size = 17239351 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/17/07/516f5b20d88932e5a466c2216b628e5358a71b3a9f522215607c3281de05/fastmcp-3.1.0-py3-none-any.whl", hash = "sha256:b1f73b56fd3b0cb2bd9e2a144fc650d5cc31587ed129d996db7710e464ae8010", size = 633749 }, { url = "https://files.pythonhosted.org/packages/0a/5a/f410a9015cfde71adf646dab4ef2feae49f92f34f6050fcfb265eb126b30/fastmcp-3.0.2-py3-none-any.whl", hash = "sha256:f513d80d4b30b54749fe8950116b1aab843f3c293f5cb971fc8665cb48dbb028", size = 606268 },
] ]
[[package]] [[package]]
@@ -664,7 +663,7 @@ dev = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "fastmcp", specifier = ">=2.0.0" }, { name = "fastmcp", specifier = ">=2.0.0,<3.1.0" },
{ name = "httpx", specifier = ">=0.27" }, { name = "httpx", specifier = ">=0.27" },
{ name = "pyyaml", specifier = ">=6.0" }, { name = "pyyaml", specifier = ">=6.0" },
{ name = "typer", specifier = ">=0.12" }, { name = "typer", specifier = ">=0.12" },
@@ -1297,15 +1296,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611 }, { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611 },
] ]
[[package]]
name = "uncalled-for"
version = "0.2.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/02/7c/b5b7d8136f872e3f13b0584e576886de0489d7213a12de6bebf29ff6ebfc/uncalled_for-0.2.0.tar.gz", hash = "sha256:b4f8fdbcec328c5a113807d653e041c5094473dd4afa7c34599ace69ccb7e69f", size = 49488 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ff/7f/4320d9ce3be404e6310b915c3629fe27bf1e2f438a1a7a3cb0396e32e9a9/uncalled_for-0.2.0-py3-none-any.whl", hash = "sha256:2c0bd338faff5f930918f79e7eb9ff48290df2cb05fcc0b40a7f334e55d4d85f", size = 11351 },
]
[[package]] [[package]]
name = "uvicorn" name = "uvicorn"
version = "0.41.0" version = "0.41.0"

View File

@@ -4,11 +4,11 @@ type: workplan
title: "Agent Usability — MCP Registration, Skill, and Worker Orientation" title: "Agent Usability — MCP Registration, Skill, and Worker Orientation"
domain: custodian domain: custodian
repo: ops-bridge repo: ops-bridge
status: active status: done
owner: custodian owner: custodian
topic_slug: custodian topic_slug: custodian
created: "2026-03-21" created: "2026-03-21"
updated: "2026-03-21" updated: "2026-03-26"
depends_on: OPS-WP-0001 depends_on: OPS-WP-0001
state_hub_workstream_id: "c195cc40-8be7-462e-be26-a7d6bda34cd5" state_hub_workstream_id: "c195cc40-8be7-462e-be26-a7d6bda34cd5"
--- ---
@@ -74,7 +74,7 @@ worker agents:
```task ```task
id: OPS-WP-0002-T01 id: OPS-WP-0002-T01
status: todo status: done
priority: high priority: high
state_hub_task_id: "27fc6fa1-6d0e-438a-b4a3-c6091931da88" state_hub_task_id: "27fc6fa1-6d0e-438a-b4a3-c6091931da88"
``` ```
@@ -101,7 +101,7 @@ Gate: `bridge_status()` tool callable via SSE on localhost:8002 after
```task ```task
id: OPS-WP-0002-T02 id: OPS-WP-0002-T02
status: todo status: done
priority: high priority: high
state_hub_task_id: "2216457d-035e-4804-b685-18975f3c6d1f" state_hub_task_id: "2216457d-035e-4804-b685-18975f3c6d1f"
``` ```
@@ -133,7 +133,7 @@ mcp-http`.
```task ```task
id: OPS-WP-0002-T03 id: OPS-WP-0002-T03
status: todo status: done
priority: medium priority: medium
state_hub_task_id: "4b2e39eb-4585-4e60-ab16-9e7909eced74" state_hub_task_id: "4b2e39eb-4585-4e60-ab16-9e7909eced74"
``` ```
@@ -178,7 +178,7 @@ identifies and recovers a manually-stopped tunnel.
```task ```task
id: OPS-WP-0002-T04 id: OPS-WP-0002-T04
status: todo status: done
priority: medium priority: medium
state_hub_task_id: "cc64bb07-ea5d-498a-8c14-bb653581efe7" state_hub_task_id: "cc64bb07-ea5d-498a-8c14-bb653581efe7"
``` ```
@@ -213,9 +213,9 @@ session protocol references bridge status check.
## Done Criteria ## Done Criteria
- [ ] `make mcp-http` starts the MCP server on port 8002 (SSE) - [x] `make mcp-http` starts the MCP server on port 8002 (SSE)
- [ ] `bridge_status` and `bridge_check` callable as MCP tools from Claude Code - [x] `bridge_status` and `bridge_check` callable as MCP tools from Claude Code
- [ ] `ops-bridge` registered in `~/.claude.json` at user scope - [x] `ops-bridge` registered in `~/.claude.json` at user scope
- [ ] `/bridge` skill surfaces tunnel states and recovers a stopped tunnel - [x] `/bridge` skill surfaces tunnel states and recovers a stopped tunnel
- [ ] Global CLAUDE.md has worker agent bridge protocol - [x] Global CLAUDE.md has worker agent bridge protocol
- [ ] All existing tests pass after T01 changes (`make test`) - [x] All existing tests pass after T01 changes (`make test`)