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
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
repository: Knuckles-Team/agent-utilities
ref: fbc939fedeadeb20ddf4b468245165414a18c34e
ref: 2d40ed53f6440fdda0b5cfb7868d912fa8f162e1
path: .uv-workspace-siblings/agent-utilities
persist-credentials: false

Expand All @@ -115,7 +115,7 @@ jobs:
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
repository: Knuckles-Team/epistemic-graph
ref: 49d63da5396fef7482fc3617df3f90a836661722
ref: 70037e8a400c7b32b1222623bb05bbfaf55deab8
path: .uv-workspace-siblings/agent-utilities/.uv-workspace-siblings/epistemic-graph
persist-credentials: false

Expand Down
50 changes: 44 additions & 6 deletions graph_os/deployment/production_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,31 @@ async def _restore_validate(archive_root: Path, scratch_root: Path) -> dict[str,
shutil.rmtree(destination, ignore_errors=True)


async def _provision_semantic_content(served_url: str) -> dict[str, Any]:
"""Provision GraphOS's semantic packs under its own verified process session.

The session and engine come from the same bootstrap the served process
uses, so every EG call carries exactly the authority GraphOS serves with.
"""

from agent_utilities.api.session import use_session
from agent_utilities.security.brain_context import use_actor

from graph_os.deployment.semantic_provisioning import provision_semantic_content

# ``runtime`` binds bootstrap's host slots on import; import it first.
from graph_os.mcp_server import bootstrap, runtime

session = runtime._mint_process_session("http")
with use_actor(session.actor), use_session(session):
engine = runtime._get_engine()
bootstrap._wait_for_engine_materialization(engine)
report = await provision_semantic_content(
engine=engine, session=session, served_url=served_url
)
return {"operation": "provision-semantic-content", "ok": True, **report}


def _parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(prog="graph-os-production-ops")
subparsers = parser.add_subparsers(dest="operation", required=True)
Expand All @@ -388,18 +413,31 @@ def _parser() -> argparse.ArgumentParser:
restore = subparsers.add_parser("restore-validate")
restore.add_argument("--archive-root", type=Path, required=True)
restore.add_argument("--scratch-root", type=Path, required=True)
provision = subparsers.add_parser("provision-semantic-content")
provision.add_argument(
"--served-url",
default=str(setting("GRAPH_OS_SERVED_MCP_URL", "") or ""),
help="MCP URL GraphOS serves its content at (registered when absent).",
)
return parser


def _run(args: argparse.Namespace) -> dict[str, Any]:
if args.operation == "backup":
return asyncio.run(_backup(args.archive_root))
if args.operation == "restore-validate":
return asyncio.run(_restore_validate(args.archive_root, args.scratch_root))
if not args.served_url:
raise ProductionOperationError(
"--served-url (or GRAPH_OS_SERVED_MCP_URL) is required"
)
return asyncio.run(_provision_semantic_content(args.served_url))


def main(argv: list[str] | None = None) -> int:
args = _parser().parse_args(argv)
try:
if args.operation == "backup":
report = asyncio.run(_backup(args.archive_root))
else:
report = asyncio.run(
_restore_validate(args.archive_root, args.scratch_root)
)
report = _run(args)
except Exception as exc: # noqa: BLE001 - CLI returns one privacy-safe failure
report = {
"operation": args.operation,
Expand Down
Loading
Loading