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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

synoi_gap-0.1.0.tar.gz (22.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

synoi_gap-0.1.0-py3-none-any.whl (15.3 kB view details)

Uploaded Python 3

File details

Details for the file synoi_gap-0.1.0.tar.gz.

File metadata

  • Download URL: synoi_gap-0.1.0.tar.gz
  • Upload date:
  • Size: 22.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for synoi_gap-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6603b491f44f4671befc59ea5523ab620e06d726b07d2b2a8dc9d4891de8753d
MD5 8e1eb3ad8732824aea6f7f09819c1e82
BLAKE2b-256 9ed7772ae7bd267eb046cc105277cba8e3e4e04dee25d313db6dfcb54ba22271

See more details on using hashes here.

File details

Details for the file synoi_gap-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: synoi_gap-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for synoi_gap-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 143f418bff1525888766e0611af6ffcc73dfc4984c01009875117aedc4558cae
MD5 10433b29207dfd260f1f6eb6611d9a5a
BLAKE2b-256 34482703a7082bfe80f2b79ad4e5ad1eeba6bdb3d68389af79162e411fb32689

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page