Skip to content

Latest commit

 

History

258 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Pharos

Real-time policy verdicts for AI agents, with cryptographic evidence of every decision.

Pharos decides. Pharos proves.

License CI


When an AI agent is about to do something consequential — move money, send PHI, change a record — Pharos answers two questions in one call. Can it? A policy verdict (allow, block, modify, escalate) citing the specific rule clause it relied on. What happened? A signed, hash-chained evidence record binding that action to its mandate, its verdict, and its blast radius — written to WORM storage and verifiable by anyone, offline, later.

One pipeline, two outputs, and that is the whole point: an agent action can never be governed without being recorded, or recorded without its governing context.

Who it's for. Teams putting agents somewhere consequential — payments, healthcare, regulated workflows — who will need to answer "why did the agent do that?" months later, to someone who will not simply take your word for it.

Why it's different. Guardrail libraries block bad output but leave no durable trail. Governance tooling documents policy but never touches runtime. Pharos closes the loop: the same event that decides is the one that proves, signed once and chained once.

flowchart LR
    A["Agent<br/><i>any framework</i>"] -->|SDK or gateway| B

    subgraph decide ["DECIDE — a verdict, in one call"]
        direction TB
        B["Tier 1<br/>deterministic rules<br/><i>mandates, limits</i>"] --> C["Tier 2<br/>statistical risk"]
        C --> D["Tier 3<br/>judge model"]
    end

    D --> E{"Verdict<br/>allow · block<br/>modify · escalate"}
    E -->|same transaction| F["Sealed ActionRecord<br/><i>hash + signature</i>"]

    subgraph prove ["PROVE — evidence that outlives the request"]
        direction TB
        F --> G[("Hash chain<br/>genesis → head")]
        G --> H[("WORM storage<br/>S3 Object Lock")]
        G --> I["RFC 3161<br/>trusted-time anchor"]
    end

    H --> J["Offline verification<br/><i>no Pharos required</i>"]
    I --> J
Loading

Quickstart

A governed action and a verified evidence chain, locally. No cloud account, no API key, no paid service.

git clone https://github.com/Bobcatsfan33/Pharos.git && cd Pharos
pnpm install
cp .env.example .env
pnpm infra:up          # Postgres + Redis + MinIO (S3 WORM) via docker compose

Govern three agent actions and seal them:

pnpm demo:durability
=== Submitting 3 demo actions for tenant "demo-tenant" ===
  seq 0  email.send          -> ALLOW      hash 7928edf0c664…
  seq 1  payment.transfer    -> BLOCK      hash 858d1aae0430…
  seq 2  crm.update          -> ALLOW      hash 7d3ac5477574…

Chain head: sequence 2 hash 7d3ac54775745ded…

That payment.transfer -> BLOCK is a Tier-1 deterministic rule: the action exceeded its mandate's limit. The verdict and the sealed record came out of the same transaction.

Now prove the evidence survived a restart and the chain is intact genesis-to-head:

pnpm demo:durability --verify
=== Cold verification for tenant "demo-tenant" (simulated restart) ===
Found 3 persisted records after restart.
Genesis-to-head chain verification: PASS ✅
  records checked: 3

Measured on a clean checkout (2026-08-02, warm pnpm store, Docker images already pulled): pnpm install 2s · infra:up 1s · demo 2s · verify 1s. Budget about five minutes for a genuinely first run — almost all of it Docker pulling the Postgres, Redis and MinIO images; the commands themselves take seconds.

If --verify reports a chain break, you are pointing a fresh checkout at a database seeded by a different one. That is correct behaviour rather than a bug — the earlier records were signed by a keystore that no longer exists, so their signatures no longer verify. Start from a clean database, or remove .pharos-keystore and re-run.

Then see the whole story

pnpm demo

An agent tries to wire $4,800 with no mandate. Pharos refuses and cites the rule:

── Act 1 ─ the agent acts without authority

  Verdict:   ESCALATE   tier 3
  Cited:     finra-3110-funds-movement  FINRA Rule 3110 (supervision) / 2150 (funds handling)
             Movement of customer funds requires supervisory review. Unmandated
             funds-movement intent is escalated to a registered principal.

Treasury grants a mandate. Same transfer, same agent, same amount — the verdict flips:

── Act 2 ─ treasury grants a mandate

  Verdict:   ALLOW   tier 3

Both decisions are sealed, anchored in trusted time, and written to a bundle that anyone can check offline, with no Pharos infrastructure:

pnpm verify:bundle evidence-bundle.json
Chain verification: PASS - admissible

Trusted-time anchors (1):
  OK  anchor [local] 8880a43f2d33… @ 2026-08-02T20:53:45.971Z  (head)

Anchor verification: PASS - head existed before the stamped time

Full walkthrough, including how to tamper with the bundle and watch it fail: docs/demo.md.

Use it from your agent

import { PharosClient } from "@getpharos/sdk";

const pharos = new PharosClient({ baseUrl, apiKey });

const { verdict, record } = await pharos.submit({
  tenantId: "acme",
  action: { type: "payment.transfer", agentId: "treasury-bot", payload: { amount: 30_000 } },
  liability: {
    mandate: null,
    oversightMode: "autonomous",
    blastRadius: { financialAmount: 30_000, currency: "USD", reversibility: "irreversible" },
    modelMetadata: null,
  },
});

if (verdict.decision === "block") throw new Error(verdict.ruleCitations[0]?.description);
// record.seal.contentHash is now permanent, signed evidence.
from pharos_sdk import PharosClient

pharos = PharosClient(base_url=base_url, api_key=api_key)

result = pharos.submit(
    tenantId="acme",
    action={"type": "payment.transfer", "agentId": "treasury-bot",
            "payload": {"amount": 30000}},
    liability={"mandate": None, "oversightMode": "autonomous",
               "blastRadius": {"financialAmount": 30000, "currency": "USD",
                               "reversibility": "irreversible"},
               "modelMetadata": None},
)

if result["verdict"]["decision"] == "block":
    raise RuntimeError(result["verdict"]["ruleCitations"][0]["description"])

Both SDKs are deadline-aware, retry transient failures, and apply a local fail-mode when Pharos is unreachable: reversible work fails open, irreversible work fails closed. Framework middlewares (LangChain/LangGraph, OpenAI Agents, Anthropic SDK, CrewAI, MS Agent Framework) share one conformance contract, and a zero-code HTTP gateway governs agents that import nothing at all. See docs/sdks-and-integration.md.

Pharos Runtime: governed execution included

Pharos now ships its durable Python runtime in this monorepo under runtime/python. It submits every runnable step through /v1/actions, writes the sealed evidence binding into its append-only execution log, and maps escalation to a zero-compute durable pause. After review, the same run resumes with a stable replay-safe claim identity. The control plane and runtime remain independently scalable while sharing one product, release boundary, and end-to-end CI proof.

python3 -m pip install -e "runtime/python[viewer]"
pharos run --mock runtime/python/examples/pharos_governed.py --run-id governed-demo

The legacy keel command remains available for compatibility. See the Pharos Runtime contract and quickstart.

Status — what is and isn't proven

Pharos is not a finished product, and its own readiness manifest says so. That manifest is machine-checked in CI and currently reads decision: not-approved with 6 open blocking gates. It ships published rather than hidden, because a system whose pitch is evidence should be willing to be evidence about itself.

Works today, tested Verdict cascade · sealing · hash chain · WORM · offline verification · TS + Python SDKs · framework middlewares · zero-code gateway · OPA/Cedar interchange · signed policy bundles · MCP/tool governance · governed connectors · approval policy · causal evidence graph · assurance promotion/rollback · technical control mappings · open governed-action protocol
Test suite 545 control-plane tests plus the complete runtime and Python SDK suites—run against real Postgres / Redis / MinIO. CI fails the build if integration tests are skipped rather than run
Not production-approved docs/enterprise-readiness.json · docs/procurement-readiness.md
Every known gap docs/LIMITATIONS.md

On the judges, plainly. The Tier-3 judges on the default local path are linear bag-of-words classifiers. They are the honest demo path — fast, deterministic, easy to reason about, and defeated by paraphrase. The transformer judges are wired and served but remain restricted pre-production: their model cards list the adversarial-efficacy, calibration, and independent-validation evidence still missing. No judge is promoted or marketed as production-ready. The deterministic Tier 1 and statistical Tier 2 carry the load a demo actually exercises.

On latency. The old p99 3.7 ms / ~5,400 verdicts-per-second linear-model headline has been retired. The benchmark now loads all three ONNX judges by default. A current Apple-M2 engineering run stayed below 800 ms p99 at concurrency 2 but achieved only about 8 verdicts/second, so the 1,000 verdicts/second production-topology gate remains open. See docs/benchmarks/latency.md.

How it's built

Operational state Postgres — policies, mandates, queues, tenants; RLS-isolated under a NOBYPASSRLS role
Evidence chain WORM object storage (S3 Object Lock), hash-chained and continuously verified
Verdict cache Redis, deadline-bound
Signing Pluggable SigningProvider — local Ed25519, AWS KMS P-256, and remote BYOK/HYOK transports for Vault Transit, Azure Key Vault, and GCP KMS, with rotation and chain continuity
Deployment Docker Compose or Helm — see deploy/INSTALL.md
packages/core        ActionRecord schema, hashing, sealing, chain verify, KMS signing
packages/cascade     the tiered verdict engine
packages/connectors  MCP registry, credential grants, governed effects, plugin conformance
packages/devkit      policy simulation/diff, fixture sanitation, environment doctor
packages/storage     Postgres + S3 WORM + Redis; the transactional write path
packages/sdk-ts      TypeScript SDK          sdks/python   Python SDK
packages/middleware  framework adapters
services/api         Fastify ingestion API   services/gateway  zero-code egress gateway
apps/console         Next.js console

Docs

Architecture How the pieces fit together
Capability platform Policy interop, MCP, connectors, approvals, assurance, compliance, and the open protocol
Demo walkthrough The funds-transfer story, end to end
Decision cascade Tiers, deadlines, fail-modes
Evidence & sealing Chain, anchoring, redaction, claims packs
Offline verification Verify a bundle with no Pharos infrastructure
Schema The ActionRecord event
Threat model STRIDE analysis and the accepted-risk register
Limitations Everything that does not yet work as a buyer would want
Sprint history What was built, sprint by sprint
Contributing Setup, the review bar, and how this repo is run

Contributing

Good first issues are labelled and scoped with acceptance criteria. The house rules — DCO sign-off, a changeset for publishable packages, integration tests that run rather than skip, and rendering configuration rather than reading it — are in CONTRIBUTING.md. Apache-2.0; the open-core boundary is a proposal that relicenses nothing. Be decent — see the Code of Conduct.


Pharos decides. Pharos proves.

About

The trust control plane for enterprise AI agents — real-time policy verdicts in under 800ms and litigation-grade evidence of every decision. Pharos decides. Pharos proves.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages