Skip to main content

ForceEquals SDK — builder integration guide

How to govern your coded agent with ForceEquals. Share this with customers and internal agent authors.

You write the agent. ForceEquals decides whether each step may continue, must pause for a human, or must be blocked.

Your agent reports facts  →  ForceEquals applies org policy  →  Your agent obeys

You do not write pause/poll/resume loops. That lives in the SDK.


1. What you install vs what ForceEquals hosts

Piece Who runs it What it is
SDK (pip install forceequals) You, inside your agent process Small Python library
ForceEquals API ForceEquals (or your local mock_server.py) Policy + approvals
Momentum ForceEquals web app Create API key, policies, approve cards

The SDK is not a server. You do not deploy it. You install it. ForceEquals deploys the API and Momentum.


2. What you need (credentials)

Create these in Momentum while logged in (your email owns the key).

Item Example Where
API key fe_live_... Momentum → API Key → Generate. Shown once.
Agent id github-agent Momentum → Add Agent / Connect. Must match FORCEEQUALS_AGENT_ID.

Put them in your agent .env (never commit the key):

FORCEEQUALS_API_KEY=fe_live_your_key_here
FORCEEQUALS_AGENT_ID=github-agent

The SDK calls the hosted ForceEquals API. You do not set FORCEEQUALS_BASE_URL. That URL is built into the SDK. (Optional local override: FORCEEQUALS_BASE_URL=http://127.0.0.1:8787 when running mock_server.py.)

You do not send your email in the SDK. The API key is your identity. The API looks up the key and knows which Momentum user owns it.

Not ForceEquals credentials (those stay yours):

  • GitHub token, OpenAI/Claude key, database passwords — your agent’s own tools.

If the key is missing, revoked, or not created under your Momentum login, SDK calls return 401.


3. Install

pip install forceequals

Until the package is on PyPI, from this repo:

cd forceequals-platform
pip install -e .

Python 3.10+.


4. Integrate — step by step

Step 1 — Create the client once

from forceequals import (
    ForceEquals,
    GovernanceBlockedError,
    GovernanceRejectedError,
)

fe = ForceEquals()  # reads FORCEEQUALS_API_KEY + FORCEEQUALS_AGENT_ID

Step 2 — Wrap each business run with @fe.governed

One GitHub PR, one loan application, one user message = one run.

class MyAgent:
    @fe.governed
    def handle_event(self, payload: dict) -> None:
        ...

This allocates execution_id / case_id. Without it, emit_event fails.

Keep your process alive yourself (a while True or worker). ForceEquals only governs this run.

Step 3 — Report facts with emit_event

Call this after something meaningful happened. ForceEquals policies decide continue / pause / block.

decision = fe.emit_event(
    "pull_request.opened",
    {
        "repo": payload["repo"],
        "pr": payload["number"],
        "title": payload["title"],
        "base_branch": payload["base_branch"],
    },
)
# If this returns, status was continue (or pause was approved).
# If policy blocked, GovernanceBlockedError is raised.

Do not check policy yourself. Send facts only.

Step 4 — Explicit human gate with request_approval

Use this when you already know a human must approve (merge to main, pay out money). Always pauses.

fe.request_approval(
    title=f"Merge PR #{payload['number']} into {payload['base_branch']}",
    context={"pr": payload["number"], "repo": payload["repo"]},
)

The SDK waits until a reviewer approves, denies, or requests changes in Momentum (or approve.py locally).

Step 5 — Catch block / reject so the process stays up

def run_one(agent, payload):
    try:
        agent.handle_event(payload)
    except GovernanceBlockedError as exc:
        print(f"Blocked by policy: {exc}")
    except GovernanceRejectedError as exc:
        print(f"Rejected by reviewer: {exc}")

Blocked/rejected stops this run, not the agent process.

Step 6 — Keep doing your work

LLM review, GitHub API, tools — that is your code. After a successful request_approval, continue (comment, merge, notify). ForceEquals does not merge GitHub for you.


5. Minimal example

from forceequals import ForceEquals, GovernanceBlockedError, GovernanceRejectedError

fe = ForceEquals()

class GitHubAgent:
    @fe.governed
    def handle_pull_request(self, pr: dict) -> None:
        fe.emit_event("pull_request.opened", {
            "repo": pr["repo"],
            "pr": pr["number"],
            "title": pr["title"],
        })
        # your review / tools here
        fe.request_approval(
            title=f"Merge PR #{pr['number']}",
            context={"pr": pr["number"]},
        )
        print("Governance allowed this merge (you still perform it).")

agent = GitHubAgent()
try:
    agent.handle_pull_request({"repo": "acme/app", "number": 42, "title": "Fix"})
except GovernanceBlockedError as exc:
    print("Blocked:", exc)
except GovernanceRejectedError as exc:
    print("Rejected:", exc)

6. What ForceEquals returns

Status Meaning What the SDK does
continue Allowed Returns; your next line runs
paused Human needed Waits; card appears in Momentum
blocked Hard no Raises GovernanceBlockedError

request_approval always pauses. emit_event is adaptive (policies + Policy LLM).

Optional: a policy may return override_result (forced answer/tool output). The SDK applies that; you do not.


7. Local test (before production URL)

  1. Log into Momentum locally → create API key → copy fe_live_... (or use FE_LOCAL_KEY for a local-only demo).
  2. Start the ForceEquals API: python mock_server.py (port 8787).
  3. Optional: FORCEEQUALS_BASE_URL=http://127.0.0.1:8787 so a fe_live_ key hits the local mock instead of the hosted API. FE_LOCAL_KEY already defaults to localhost.
  4. Run your agent. On pause, approve in Momentum when wired, or:
python approve.py <approval_id>
  1. Agent should print that it resumed.

8. Checklist

  • Momentum account and API key (fe_live_...)
  • FORCEEQUALS_AGENT_ID matches the agent registered in Momentum
  • pip install forceequals
  • ForceEquals() once at process start
  • @fe.governed on each run
  • emit_event after real work facts
  • request_approval on irreversible steps
  • Catch GovernanceBlockedError / GovernanceRejectedError
  • Your own loop keeps the agent online for the next event

9. Related

Doc Audience
PUBLISH_AND_DEPLOY.md ForceEquals team — PyPI + API hosting
FLOW_GUIDE.md Internal product flow
NO_CODE_INTEGRATION.md n8n / Agentforce (HTTP, no Python SDK)

Download files

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

Source Distribution

forceequals-0.1.0.tar.gz (18.3 kB view details)

Uploaded Source

Built Distribution

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

forceequals-0.1.0-py3-none-any.whl (17.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: forceequals-0.1.0.tar.gz
  • Upload date:
  • Size: 18.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for forceequals-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8259b9882473bfe1c065b95c67f92d65f1f8201e8471eb9698610de3b93cc66a
MD5 4a99ef9576489324d87a17cdb878d08d
BLAKE2b-256 5462baeda61f2c8e480a8f9733cd4da4c97b2b12b0b3b16e54003541a2b49e55

See more details on using hashes here.

File details

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

File metadata

  • Download URL: forceequals-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 17.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for forceequals-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 089e8dcca3b35616862b587d2f813daadc5391bb7855c800c796b86803d0d56c
MD5 560fe974536f2aeebbd125572a6f8c52
BLAKE2b-256 7a9cd21fb834482e1526a767f5c8f6c8a2db7ce94f264f7a6258ee1f6bac7333

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 Sentry Error logging StatusPage Status page