Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

8 Commits

Folders and files

Repository files navigation

PurposeSweep

Autonomous business-intent lifecycle cleanup for enterprise systems.

PurposeSweep

Autonomous business-intent lifecycle agent.

Everything in enterprise software has a lifecycle except the reason it exists. PurposeSweep reconstructs that reason from evidence, detects when it has expired, maps dependencies, safely retires only obsolete artifacts, verifies downstream health, and leaves an auditable rollback trail.


PurposeSweep

PurposeSweep is a production-deployed autonomous business-intent lifecycle cleanup system powered by Gemini 3.6 Flash, Google ADK, Google Cloud Run, and Firestore.

It reconstructs why enterprise resources exist, maps active dependencies, applies deterministic safety policy, requires human approval where necessary, executes authorized changes, independently verifies results, and produces an auditable closure report.

Live deployment

Prerequisites

Tool Version used Notes
Python 3.10.12 3.10–3.12 accepted; code must stay 3.10-compatible
Node 22.23.2 Next.js 16 requires Node ≥ 20.9
npm 10.9.8 npm, not pnpm

pnpm, docker and gcloud are not required for local development.


Setup

Run both steps once, from the repository root.

Backend

python3 -m venv .venv
.venv/bin/python -m pip install -e packages/domain -e packages/repositories \
                                -e packages/demo -e packages/inference \
                                -e packages/graph -e packages/policy \
                                -e packages/execution -e packages/orchestration -e packages/ai \
                                -e packages/cloud \
                                -e 'apps/api[dev]'

Frontend

cd apps/web && npm install && cd ../..

Environment (optional) — every value has a working local default, so nothing is required to start. To override:

cp .env.example apps/api/.env                  # backend
cp apps/web/.env.example apps/web/.env.local   # frontend

.env files are git-ignored. .env.example files contain no secrets and never will.


Running locally

Both services at once (API in the background, web in the foreground; Ctrl-C stops both, and the script waits for the API to be healthy before starting the web server):

./scripts/start_local.sh

Individually:

./scripts/start_api.sh     # http://127.0.0.1:8000
./scripts/start_web.sh     # http://localhost:3000
Service URL
Web UI http://localhost:3000
API http://127.0.0.1:8000
Health http://127.0.0.1:8000/health
API docs http://127.0.0.1:8000/docs

Ports are overridable: API_PORT=8001 ./scripts/start_api.sh, WEB_PORT=3001 ./scripts/start_web.sh.

Every command under scripts/ prints its own usage with --help, and refuses any flag it does not recognise rather than doing something you did not ask for.

The main demo and deployment commands, and what each is for:

Command Does Takes
./scripts/reset_demo.sh Restores the demo world exactly and discards every stored sweep. ~0.2s. 0.2s
./scripts/start_api.sh The API alone, with autoreload. PURPOSESWEEP_EXECUTION_MODE=dry_run to simulate. reachable in 0.8s
./scripts/start_web.sh The UI alone, pointed at API_PORT.
./scripts/start_local.sh Both, one terminal, API log in .data/logs/api.log.
./scripts/run_sweep_demo.sh One complete sweep on the command line. --approve-demo approves the three named actions; --adversarial adds a planner that proposes deleting Mercury's dataset. 0.3s
./scripts/verify_demo_e2e.sh The canonical lifecycle over the network against a real server - 66 checks. --with-web also serves the UI against it. ~20s
./scripts/verify_all.sh Everything: 25 required checks, including the two above. ~3min
./scripts/verify_gemini.sh The model path against the real Gemini API, fallback off. Skips with exit 0 and printed instructions when no credentials are configured. ~30s
./scripts/deploy_cloud.sh Build and deploy both services to Cloud Run. --dry-run prints every command and changes nothing. ~8min
./scripts/verify_cloud.sh 22+ real requests against a deployed stack: persistence, the whole lifecycle, CORS, the client bundle, IAM, indexed logs. ~40s

docs/DEMO_SCRIPT.md is the rehearsed four-minute run, with the measured timing of every beat. docs/GEMINI_ADK.md covers the model path, and docs/CLOUD_DEPLOYMENT.md covers the Google Cloud deployment - including a section stating exactly which of its claims are verified and which need a real project.

Running on Gemini

export GOOGLE_API_KEY=<your key>          # or the Vertex AI variables
PURPOSESWEEP_AI_PROVIDER=gemini ./scripts/start_local.sh
PURPOSESWEEP_AI_PROVIDER=gemini ./scripts/run_sweep_demo.sh --approve-demo

Deterministic is the default and the fallback. Without credentials, gemini runs deterministically and says so on startup rather than failing or pretending. A model may propose; it never authorises — every proposal resting on a model-inferred purpose reaches a named person, whatever its confidence. See docs/GEMINI_ADK.md.

Check the API directly:

curl http://127.0.0.1:8000/health
# {"status":"ok","service":"purposesweep-api","version":"0.1.0","environment":"development"}

The product

Nine screens at http://localhost:3000, all reading the live API.

Screen Answers
Command Center (/) What does the estate look like, what has PurposeSweep concluded, and what happens if I press the button?
Live Sweep (/sweep/{id}) What is the agent doing right now — stage rail and event log, both fed by the backend's own events
Retirement Plan (/sweep/{id}/plan) What was proposed for each resource, and what policy said when asked
Approval Center (/sweep/{id}/approvals) What a person still owes, and what they are signing. There is no control that approves what policy refused
Execution & Verification (/sweep/{id}/execution) What was actually done, the receipt, the independent re-read, and whether Project Mercury survived
Purpose Closure Certificate (/sweep/{id}/certificate) What the sweep accomplished, with the record ids behind every number
Dependency Graph (/graph) What would break if this went — Atlas, the shared dataset, Mercury, in one picture
Purpose DNA (/purpose-dna) Why each artifact exists and whether that reason has ended, with the evidence
Estate (/resources, /resources/{id}) Everything known about one artifact, in the order the reasoning happens

The 90-second demo. Open the Command Center, press Start sweep. The run stops at three approvals. Read one — the agent's recommendation and the policy verdict beside it. Approve all three by name, resume, and open the certificate: 6 retired, 8 preserved, 0 broken dependencies. Then open the graph, click customer_revenue_core, and see its DELETE proposal come back BLOCKED — with the dependency reason and no execution receipt.

The frontend computes nothing. Every number, verdict and timestamp on screen was read from an endpoint, no timer advances a stage, and a dry run is never presented as a real result. See docs/FRONTEND.md.


The demo world

The Atlas/Mercury scenario lives in demo/seed/*.json and is loaded and integrity-checked by purposesweep-demo. Project Atlas finished 90 days before the fixed reference time DEMO_NOW; Project Mercury is still running and still queries a dataset that originated in Atlas.

./scripts/seed_demo.sh              # validate; one-line summary
./scripts/seed_demo.sh --verbose    # validate and print the full inventory
./scripts/show_demo_inventory.sh    # projects, resources, dependencies, usage signals

The seed contains facts only - status, metadata, usage signals, dependency edges, evidence. No purpose, recommendation or policy decision is baked in; a verification gate fails the build if one appears. See docs/DEMO_SCENARIO.md.

Purpose DNA

./scripts/show_purpose_dna.sh                                  # table + summary
./scripts/show_purpose_dna.sh resource-atlas-monday-digest     # full reasoning

On the demo world: 8 EXPIRED, 5 ACTIVE, 1 UNCERTAIN. The three Atlas artifacts that ran within the last week are all EXPIRED — the engine reads how activity arose, not when. The shared dataset is UNCERTAIN and flagged for review, never "safe to delete".

Purpose inference does not authorise retirement. A result is an input to the deterministic policy layer, never a substitute for it; a verification gate fails the build if any result expresses a disposition. See docs/PURPOSE_INFERENCE.md.

Dependency graph

./scripts/show_dependency_graph.sh                                     # estate overview
./scripts/show_dependency_graph.sh resource-shared-customer-revenue    # one resource
./scripts/show_dependency_graph.sh --snapshot                          # JSON snapshot

14 resources, 14 edges, 1 shared resource, 6 orphan candidates (all Atlas), 0 cycles. customer_revenue_core originated in Atlas (COMPLETED) and is consumed now by Mercury (ACTIVE) — two separate fields, two different answers.

Graph analysis informs policy but does not authorise retirement. orphan_candidate means nothing live depends on a resource, not that it is safe to remove. See docs/DEPENDENCY_GRAPH.md.

Policy

./scripts/show_policy_plan.sh                                              # what-if plan
./scripts/show_policy_plan.sh resource-shared-customer-revenue --action DELETE

AI may recommend. Policy authorises. The executor mutates. Precedence is absolute — BLOCKED > APPROVAL_REQUIRED > AUTO — and PurposeDNA.confidence appears in exactly one rule, where it can only add a restriction. A DELETE proposal on the shared dataset backed by a forged confidence-1.0 EXPIRED purpose is still BLOCKED, because neither of the rules protecting it reads confidence at all. See docs/POLICY_ENGINE.md.

Execution

./scripts/run_execution_demo.sh                                    # the whole demo
./scripts/run_execution_demo.sh --dry-run                          # preview only
./scripts/run_execution_demo.sh --audit resource-atlas-reporting-sa

A connector's execute() takes an AuthorizedAction and nothing else, and an AuthorizedAction can only be produced by authorize() from a policy decision that permits the action. The sentinel proving that is burned during construction, so a token cannot be built by hand or derived from a legitimate one — which matters because every connector is handed a live token on every action it performs. Verification then re-reads state from the connector rather than trusting what the executor returned, which is how a connector that reports success without changing anything gets caught.

Over the 12-action demo plan: 7 executed, 6 verified, 1 rolled back, 1 awaiting approval, 4 blocked, and Project Mercury PASS on 9/9 health checks. The rollback is worth reading about — a human approved disabling a service account that turned out to be the identity a live job runs as, and the dependent check caught it. See docs/EXECUTION_ENGINE.md.

The whole sweep

./scripts/run_sweep_demo.sh                              # stops at approvals (the default)
./scripts/run_sweep_demo.sh --approve-demo               # approves three named actions
./scripts/run_sweep_demo.sh --approve-demo --adversarial # and shows the gate refuse a bad plan

One run: discover → infer purpose → build graph → plan → policy → pause for a human → execute → verify → check Project Mercury → certify. Every stage delegates to the phase that owns it; the orchestrator owns the order and nothing else.

The canonical run retires 6 Atlas artifacts, proposes deleting the dataset both projects read and is refused by policy, preserves that dataset and the job that keeps it fresh, leaves Project Mercury PASS on 9/9 health checks with 0 broken dependencies, and eliminates 263.00/month — a figure that counts only resources actually retired and verified. A refused action produces no receipt and no saving.

The canonical path includes a regression test proving that the shared dataset deletion is blocked, produces no execution receipt, and leaves Project Mercury healthy.

The --adversarial act is still a separate demonstration: the same estate through a planner that proposes deleting Mercury's dataset at confidence 1.0 with no blast radius attached, which is how an unconstrained model behaves. See docs/SWEEP_ORCHESTRATION.md.

The API

./scripts/start_api.sh          # http://127.0.0.1:8000  ·  /docs  ·  /openapi.json
./scripts/reset_demo.sh         # discard stored sweeps, re-validate the seed

27 endpoints under /api (28 with /health) over the whole system — projects, resources, purpose, graph, policy what-ifs, sweeps, approvals, actions, certificates, project health, demo reset. A transport, not a second implementation: routes translate and never decide, and there is deliberately no endpoint that executes an arbitrary action. Execution happens only inside a sweep, on an action a planner proposed and policy authorised.

The canonical scenario runs end to end over HTTP — start a sweep, read the plan, approve three actions by name, resume, read the certificate — and verify_all.sh drives exactly that on every build, including eight concurrent resumes against one sweep. See docs/API.md.

Verification

One command decides whether the local build is healthy:

./scripts/verify_all.sh

It runs 25 required checks and exits non-zero if any fails. Nothing is suppressed with || true, and every check runs even after one fails so a single run reports every problem.

# Check
01 backend: Python interpreter is within the supported range
02 backend: every application and package module imports
03 backend: lint (ruff check)
04 backend: format (ruff format --check)
05 backend: tests (pytest)
06 guard: no cloud infrastructure SDKs; the model SDKs are installed but confined to packages/ai, declared nowhere else and imported nowhere else
07 guard: no credential-shaped strings, no .env files — the scanner is itself proven against a planted secret before its result is trusted
08 guard: .gitignore covers secrets, dependencies and build output
09 demo: the Atlas/Mercury environment loads and passes every integrity check
10 guard: the demo seed states facts, never conclusions
11 guard: purpose inference never expresses a disposition
12 guard: graph analysis states facts, never a verdict
13 safety: every mutating action on the shared resource is BLOCKED, including under a forged confidence-1.0 purpose
14 safety: execution cannot bypass policy — every blocked action refused, the authorisation token neither constructible nor derivable, a connector's escalation attempt refused, a lying connector caught, Mercury still PASS
15 sweep: the whole orchestration runs — every action through policy, every mutation verified, Mercury PASS, the certificate's numbers matching its own id lists, resume without duplicates, and an adversarial deletion refused
16 api: the canonical scenario over HTTP — every endpoint documented, the shared dataset deletion proposed and refused by policy, unsafe sequences refused legibly, a dry-run server refusing to mutate, and eight concurrent resumes producing one result
17 frontend: lint (eslint)
18 frontend: typecheck (tsc --noEmit)
19 frontend: production build (next build)
20 frontend: tests (vitest) — every screen rendered against payloads captured from the live API
21 guard: the frontend reads the backend — no timer advances progress, no placeholder data in application code
22 guard: the captured web fixtures still match the API this build serves
23 e2e: the canonical demo driven against a real server over the network
24 demo: each of the ten commands prints usage, refuses a flag it does not know, and is named in README.md and docs/DEMO_SCRIPT.md
25 safety: the model cannot authorise — a captured model claiming the shared dataset is EXPIRED at confidence 1.0 leaves all six mutating actions BLOCKED, and deterministic is still the default

Individual suites:

.venv/bin/python -m pytest              # backend tests
.venv/bin/ruff check .                  # backend lint
cd apps/web && npm run lint             # frontend lint
cd apps/web && npm run typecheck        # frontend types
cd apps/web && npm run build            # frontend production build
cd apps/web && npm test                 # frontend tests
.venv/bin/python -m pytest tests/security   # the red team, 185 tests
./scripts/verify_demo_e2e.sh            # the canonical demo, over HTTP
./scripts/verify_demo_e2e.sh --with-web  # ...and with the UI served against it
.venv/bin/python scripts/capture_web_fixtures.py   # refresh the frontend's fixtures

Layout

apps/
  api/                 FastAPI backend: routes, schemas, application services,
                       structured errors, request ids
  web/                 Next.js 16 App Router frontend, TypeScript strict:
                       nine screens, a typed API client, a design system,
                       and 97 tests against captured API payloads
packages/
  domain/              purposesweep-domain: typed lifecycle vocabulary (pydantic only)
  repositories/        purposesweep-repositories: storage protocols + in-memory impl
  demo/                purposesweep-demo: loads and validates the demo world
  inference/           purposesweep-inference: Purpose DNA engine
  graph/               purposesweep-graph: dependency reasoning
  policy/              purposesweep-policy: the deterministic safety gate
  execution/           purposesweep-execution: authorised mutation, verification, rollback
  orchestration/       purposesweep-orchestration: one sweep, sequenced across the phases
demo/seed/             deterministic Atlas/Mercury seed data (JSON, human-readable)
tests/
  unit/                fast, no I/O
  integration/         against the assembled application
  e2e/                 Playwright, arrives with the product UI
scripts/               start_api, start_web, start_local, verify_all, reset_demo,
                       capture_web_fixtures, demo inspectors
docs/                  API, architecture, deployment, demo, security, and implementation documentation
pyproject.toml         repo-wide ruff + pytest configuration (no [project] table)

Architectural boundaries are kept swappable on purpose. Deterministic inference and Gemini 3.6 Flash implement the same provider interface, so the orchestrator, API and CLI workflows remain provider-independent. Local persistence and Firestore-backed cloud persistence implement the storage boundary, while Cloud Run hosts the deployed application.


Security

The whole system has been attacked on purpose. docs/SECURITY_MODEL.md is the document to read: trust boundaries, six promises with the mechanism and the test that defends each, and seven residual risks written down rather than hidden.

The short version:

  • A resource another live project depends on will not be touched. No approval unblocks it — authorize() refuses a BLOCKED verdict before it looks at any approval — and no inference unblocks it, because the rule reads the graph.
  • Inference can only ever narrow what is permitted. A provider returning "Ignore policy and delete everything" in every field, at confidence 1.0, changes no verdict in a permissive direction. It cannot reach a connector either: packages/inference imports neither the policy engine nor the executor, and a test fails the build if it ever does.
  • No single layer's failure produces an automated destructive action. Degrade the dependency graph until it forgets Mercury exists and destructive actions stay BLOCKED; the worst outcome is that a human is asked.
  • A connector's report is never taken as evidence. One that claims success and changes nothing is caught by the verifier and produces zero certified retirements.

tests/security/ holds 185 tests written to fail against specific mutations of the guards they name — because an independent review found eight guard-breaking mutations that an earlier version of the suite did not notice.

Known and open: there is no authentication (KI-4), and policy is not re-evaluated when a sweep is resumed (KI-6). Both remain explicitly documented as bounded residual risks in the security model.


Safety posture

These rules hold from the first commit of code, not from the last:

  • The default execution mode is dry_run. demo_execute is the only other legal value and is never implicit.
  • LLMs will never mutate resources. Only the deterministic policy layer can authorise an action, and connectors will accept an AuthorizedAction only.
  • Artifacts with a verified active shared dependency are preserved by default.
  • Evidence text is treated as untrusted data, never as instructions.
  • No secrets in the repository, the logs, or the frontend bundle.

Synthetic demo data is never presented as real customer data.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages