Skip to main content

synoi-gap Python SDK

Python SDK for the GAP (Governed Action Protocol). Provides OID computation, shape validators, and a thin async HTTP client for GAP-conformant gateways.

Install

pip install synoi-gap          # core: OID + validators, no dependencies
pip install synoi-gap[http]    # adds httpx for GapClient

Requires Python 3.9 or later.

OID computation

from synoi_gap import compute_gap_oid

payload = {
    "type": "gap:capability_declaration",
    "tenant_id": "tenant-abc",
    "created_at_ms": 1750000000000,
    "created_by": "sha256:actor...",
    "body": {
        "actor_type": "service",
        "actor_id": "my-service",
        "actor_name": "My Service",
        "actor_version": "1.0.0",
        "capabilities": [{"capability": "skill.create"}],
    },
}

oid = compute_gap_oid(payload)
# "sha256:<64 hex chars>"

The excluded fields (oid, gap_version, signature, signature_key_id, supersedes) are stripped automatically before hashing. You can pass the full envelope or the stripped payload: the result is the same.

Validators

from synoi_gap import validate_cdro_envelope, validate_capability_declaration

errors = validate_cdro_envelope(envelope)
if errors:
    raise ValueError(errors)

errors = validate_capability_declaration(decl)

Validators return a list of error strings. An empty list means the shape is valid. They are not exhaustive and do not certify GAP conformance: they catch the fields most commonly omitted by new implementors. For full conformance checking, run against a L1+ conformant gateway or the TypeScript validators in @synoi/gap.

GapClient (async HTTP)

import asyncio
from synoi_gap.client import GapClient

async def main():
    async with GapClient(
        base_url="https://gateway.synoi.systems/v1/gap",
        token="synoi-sk-...",
        tenant_id="tenant-abc",
    ) as client:
        # Phase 1: declare
        decl = await client.post_declaration(declaration_envelope)

        # Phase 2: grant
        grant = await client.post_grant(grant_envelope)

        # Phase 3: invoke
        receipt = await client.invoke(invocation_envelope)

        # Phase 4: read receipt
        full_receipt = await client.get_receipt(receipt["oid"])

asyncio.run(main())

See synoi_gap/client.py for the full method list (revocation, workflow signals, key fetch).

OpenJarvis integration

synoi_gap.integrations.openjarvis provides a drop-in governance hook for OpenJarvis agents. Wire it into OrchestratorAgent via the before_tool_call parameter (see examples/openjarvis_pr_patch.py for the upstream PR that adds that hook).

import asyncio
from synoi_gap.client import GapClient
from synoi_gap.integrations.openjarvis import GapToolHook, denied_tool_result

async def main():
    async with GapClient(
        base_url="https://gateway.synoi.systems/v1/gap",
        token="synoi-sk-...",
        tenant_id="tenant-abc",
    ) as gap:
        hook = GapToolHook(
            client=gap,
            tenant_id="tenant-abc",
            actor_oid="sha256:<agent-oid>",
            grant_oid="sha256:<grant-oid>",
        )

        # With the upstream hook wired:
        agent = OrchestratorAgent(engine, tools=tools, before_tool_call=hook)
        await agent.run("do the thing")

        # Or call manually before each tool:
        allowed = await hook("shell_exec", {"command": "ls -la"})
        if not allowed:
            result = denied_tool_result("shell_exec")

asyncio.run(main())

Capability map: 30 OpenJarvis tool names are mapped to GAP capability names (e.g. shell_exec -> system.shell.exec). Unknown tools map to openjarvis.<tool_name> and are evaluated by gateway policy.

Safety classes: 9 tools are Class C (HITL required before execution): shell_exec, docker_shell_exec, file_write, apply_patch, git_tool, http_request, db_query, channel_tools, skill_manage. All others are Class B (receipt issued, no human gate).

HITL polling: when the gateway defers a Class C decision, the hook polls /receipts/{oid} until a human approves or denies via SMS, Slack, or dashboard. Default timeout is 300 seconds; configurable via hitl_timeout.

See examples/openjarvis_example.py for a runnable dry-run demo (no credentials needed).

License

Apache-2.0

Release files for synoi-gap 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for synoi-gap 0.1.0
File Size Uploaded
synoi_gap-0.1.0.tar.gz 22.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for synoi-gap 0.1.0
File Interpreter ABI Platform
synoi_gap-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 37.9 kB

Release files / synoi_gap-0.1.0.tar.gz

Download URL synoi_gap-0.1.0.tar.gz
Size 22.7 kB
Tags Source
SHA-256 checksum
How to use checksums
6603b491f44f4671befc59ea5523ab620e06d726b07d2b2a8dc9d4891de8753d
BLAKE2b-256 checksum
How to use checksums
9ed7772ae7bd267eb046cc105277cba8e3e4e04dee25d313db6dfcb54ba22271
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / synoi_gap-0.1.0-py3-none-any.whl

Download URL synoi_gap-0.1.0-py3-none-any.whl
Size 15.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
143f418bff1525888766e0611af6ffcc73dfc4984c01009875117aedc4558cae
BLAKE2b-256 checksum
How to use checksums
34482703a7082bfe80f2b79ad4e5ad1eeba6bdb3d68389af79162e411fb32689
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page