Metadata-Version: 2.4
Name: halfabyte-synapse
Version: 0.2.0
Summary: A compiler and runtime for AI agent workflows: faster and cheaper runs, with side effects protected and every change checked by a firewall.
Author: Aryan Lomte, Radhesh, Aditya, Advay Chavan
Maintainer: Half a Byte
License-Expression: MIT
Keywords: ai-agents,llm,compiler,optimization,workflow,intermediate-representation,agent-runtime,scheduling,caching,profiling,observability,mcp,benchmarking,groq,ollama,crewai,langgraph,google-adk,whatsapp
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Compilers
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: System :: Benchmark
Classifier: Topic :: System :: Monitoring
Classifier: Operating System :: OS Independent
Classifier: Environment :: Console
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic>=2.5
Requires-Dist: pyyaml>=6
Requires-Dist: python-dotenv>=1
Requires-Dist: openai>=1.40
Requires-Dist: psutil>=5.9
Provides-Extra: ui
Requires-Dist: fastapi>=0.110; extra == "ui"
Requires-Dist: uvicorn[standard]>=0.29; extra == "ui"
Requires-Dist: sse-starlette>=2; extra == "ui"
Provides-Extra: ml
Requires-Dist: scikit-learn>=1.4; extra == "ml"
Requires-Dist: lightgbm>=4; extra == "ml"
Requires-Dist: numpy; extra == "ml"
Provides-Extra: bench
Requires-Dist: rank-bm25>=0.2; extra == "bench"
Requires-Dist: datasets>=2.18; extra == "bench"
Provides-Extra: cloud
Requires-Dist: pymongo>=4.6; extra == "cloud"
Provides-Extra: crewai
Requires-Dist: crewai<1.16,>=1.15; extra == "crewai"
Provides-Extra: langgraph
Requires-Dist: langgraph<1.1,>=1.0; extra == "langgraph"
Provides-Extra: adk
Requires-Dist: google-adk<2.14,>=2.13; extra == "adk"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: ruff>=0.5; extra == "dev"
Requires-Dist: mongomock>=4.1; extra == "dev"
Provides-Extra: all
Requires-Dist: halfabyte-synapse[bench,cloud,ml,ui]; extra == "all"
Dynamic: license-file

# Synapse

**A compiler and runtime for AI agent workflows.** It finds the work your agent repeats or waits for, makes it faster and cheaper, and refuses any change it can't check.

```bash
pip install halfabyte-synapse
synapse demo
```

No API key, GPU or model needed: the demo runs on a built-in fake provider. The package is `halfabyte-synapse`; the command and the import are both `synapse`.

Built by team **Half a Byte** for the BitNBuild 2026 "Around the World" final round (GDG On Campus, Fr. Conceicao Rodrigues College of Engineering), AI/ML problem statement 2.

## Why it exists

Agents run steps one after another even when nothing connects them, repeat calls they have already made, and send context nobody reads. Fixing that by hand is easy to get wrong: run two steps together, and a model may answer differently. Cache a step, and an email may never get sent.

Synapse treats a workflow as a program:

1. **Compile** it to SIR, a graph where every dependency is explicit and every step declares what it can do to the world.
2. **Profile** real runs: time on the clock, tokens from the provider, and cost from listed prices. If nobody reported a number, it stays blank.
3. **Optimize** with passes that each state when they are safe. The passes are chosen by measuring them.
4. **Check** the result with a firewall that runs both versions on real tasks and returns **APPROVE** or **BLOCK**.

## What makes it different

- **It says no.** A BLOCK shows which tasks broke. You can plant a fault and watch the firewall catch it.
- **Side effects are law.** A step that sends an email or moves money is never cached, reordered or repeated. Steps that can't be undone never run while Synapse is testing.
- **It measures what others assume.** `synapse audit` checks whether a model server keeps its answers when requests overlap. On local Ollama, 5 of 6 prompts changed under concurrency.
- **It counts its own cost.** The savings ledger counts every run Synapse makes to check an optimization, and says when that pays back, including "never".
- **It says what it can't do.** Unknown values stay blank, demo results are labelled, and `batch` is listed as marking steps only.

## Real results

Held-out tasks on Groq `qwen/qwen3.8-27b`, `memoize` and `parallelize`, cold cache. Costs use Groq's listed prices.

| Workflow | Tasks | Time (p50) | Speedup | Tokens per task | Cost per task | Tasks passing | Answers broken | Firewall |
|---|---|---|---|---|---|---|---|---|
| `research_fanout` | 41 | 2.35 s to 1.39 s | 1.82x | 2,333 to 2,040 (-12.6%) | $0.00264 to $0.00232 (-12.2%) | 36 to 36 | 0 | **APPROVE** |
| `code_review` | 41 | 1.64 s to 0.81 s | 2.15x | no change | no change | 25 to 25 | 0 | **BLOCK** |

How to read this:

- **The APPROVE rests on cost and tokens.** Both speedups fall just inside the measured noise band (47.9% and 52.7%, against time gains of 41.1% and 50.7%), so the firewall doesn't count them as proven. That's why `code_review` is blocked even though nothing broke.
- **This is a second look at these tasks.** They ran first on a local model, and we chose this provider after seeing those results.
- **Locally, the same tasks blocked.** On Ollama, `research_fanout` reached 1.51x with 2 answers broken. That break led us to find that Ollama changes answers under concurrent requests.
- **Checking has a cost.** At these savings, the `research_fanout` check pays for itself after about 1,230 runs.

Fake-provider demos measure scheduling, not a model, so don't read them as model performance. "Verified" here means on these tasks, not proven for every input.

## Effect tiers

Every step has one, and it decides what Synapse may do. An undeclared tool is assumed to be `external`.

| Effect | Means | Example | What's allowed |
|---|---|---|---|
| `pure` | Same input, same output, nothing else happens | A seeded model call, a parse | Every rewrite, except merging random samples |
| `read` | Looks at the outside world | Web search, retrieval | Reuse while still fresh, overlap |
| `write` | Changes the workflow's own state | An agent's memory | Ordered by key, overlap only on separate keys |
| `external` | Changes the outside world | An email, a POST | Nothing: never repeated, reordered or cached |
| `irreversible` | Can't be undone | An order, a payment | As `external`, and never run while testing |

## Passes

`synapse passes` prints each one's safety rule, and `synapse explain PASS` explains one.

| Pass | What it does | Default |
|---|---|---|
| `constfold` | Works out pure steps over fixed values at compile time | on |
| `dce` | Removes steps whose results nothing uses | on |
| `context_prune` | Drops arguments a prompt never references | on |
| `cse` | Merges steps that compute the same thing | on |
| `loop_cutoff` | Stops a loop once its state stops changing | on |
| `memoize` | Serves a repeat from a content-addressed cache | on |
| `parallelize` | Runs independent steps together, within limits | on |
| `downgrade` | Moves a call to a cheaper model on the same provider | on |
| `speculate` | Starts a read before its branch is decided, within a budget | off |
| `context_trim` | Clips context, kept only if the firewall approves | off |
| `early_exit` | Ends early on a calibrated confidence signal | off |
| `batch` | Marks calls that could share a request. **The runtime doesn't fuse them yet** | off |

## Tools

### Commands

| Command | What it does |
|---|---|
| `synapse demo [--workflow NAME\|all]` | Compile, optimize and compare, with no provider |
| `synapse compile`, `graph`, `graphs` | Turn a workflow into SIR, and read it back |
| `synapse import FORMAT FILE` | Turn an OTel, Langfuse or Black Box trace into SIR |
| `synapse optimize`, `run`, `compare` | Optimize, execute with measurements, compare |
| `synapse profile`, `why`, `explain` | Measured profile, why a step wasn't optimized, what a pass does |
| `synapse verify GRAPH` | Run the firewall |
| `synapse force GRAPH PASS` | Apply one pass and let the firewall judge it |
| `synapse replay GRAPH` | Check on recordings: tokens only where a prompt changed |
| `synapse receipt GRAPH` | A record of the verdict that shows if it was edited; `--check FILE --rerun` tests one |
| `synapse savings GRAPH` | What checking cost, what it saves per run, when it pays back |
| `synapse audit --model ID` | Does this model keep its answers under concurrent requests? |
| `synapse chaos GRAPH FAULT` | Break a demo workflow on purpose |
| `synapse diagnose FORMAT FILE` | Waste report on a trace, changing nothing |
| `synapse agents`, `export`, `capsule` | Multi-agent view, Mermaid, DOT or JSON export, one run as a file |
| `synapse crew`, `langgraph`, `adk` | Run a CrewAI, LangGraph or Google ADK workflow through Synapse |
| `synapse proxy --upstream URL` | Point any OpenAI client's `base_url` here to record its calls |
| `synapse ci pin\|run WORKFLOW` | Fail when a workflow gets slower, costlier or less correct |
| `synapse monitor` | Watch runs and alert on crashes, slowdowns and overspend |
| `synapse alerts`, `digest` | Test alert channels, send a summary |
| `synapse bot` | Operate Synapse from WhatsApp and Slack |
| `synapse storage`, `doctor`, `models` | What's stored, find setup problems, check model names |
| `synapse ui`, `mcp`, `skill` | Serve the API, run the MCP server, install the agent Skill |
| `synapse bench` | Benchmark suite, from a repository checkout only |

### Write a workflow

```python
from synapse import Effect, node, workflow

@node(kind="retrieval", target="web_search", effect=Effect.READ, staleness_s=3600)
def search(query: str) -> list[str]:
    ...

@node(kind="io", target="send_email", effect=Effect.EXTERNAL)
def send(text: str) -> str:
    ...

@workflow(name="my_agent")
def my_agent(question: str):
    ...
```

Multi-agent workflows wrap steps in `with agent("researcher"):`, and they're still one graph.

### Use it with no code changes

```bash
synapse proxy --upstream https://api.groq.com/openai/v1
```

Point your client's `base_url` at `http://127.0.0.1:8030/v1`. Synapse records every call and serves exact repeats only when `temperature` is 0. `GET /synapse/report` shows the waste. It sees model calls, not your tools. Streaming isn't supported yet.

### Use it from an AI agent

`synapse mcp` is an MCP server with 21 tools, such as `optimize`, `why_not_optimized`, `verify`, `savings` and `inject_fault`. `synapse skill --target openclaw` installs a lean Skill instead (`hermes`, `claude` or a folder also work). Start a new agent session afterwards.

### Operate it from WhatsApp and Slack

`synapse bot` gives you tappable WhatsApp menus through Twilio, and buttons in Slack. Send `hi`, or type a command such as `health`, `spend`, `verify research_fanout`, `chaos research_fanout crash`, `pending` or `ship`. Only signed requests from allowed numbers get in. Nothing runs live, and `ship` refuses anything the firewall hasn't approved. Email is outbound only.

```bash
synapse bot --port 8010
ngrok http 8010        # any tunnel works; set SYNAPSE_BOT_URL to its address
```

## Install options

```bash
pip install "halfabyte-synapse[ui]"          # the API server
pip install "halfabyte-synapse[cloud]"       # MongoDB or Atlas as the store
pip install "halfabyte-synapse[ml]"          # the learned pass policy
pip install "halfabyte-synapse[all]"         # all of the above, plus benchmark loaders
pip install "halfabyte-synapse[crewai]"      # or [langgraph], or [adk]
```

`crewai` and `adk` can't share an environment, because their OpenTelemetry requirements clash.

## Configuration

Settings live in `.env`, and models live in `models.yaml`. Everything is optional.

| Setting | For |
|---|---|
| `GROQ_API_KEYS`, `OPENROUTER_API_KEYS` | Comma-separated keys for those providers |
| `SYNAPSE_STORE` | `mongodb+srv://...` for a shared store. Local SQLite otherwise |
| `SYNAPSE_READ_ONLY=1` | API serves reads only, for public hosting |
| `SLACK_WEBHOOK_URL`, `SLACK_SIGNING_SECRET` | Slack alerts, commands and buttons |
| `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `TWILIO_WHATSAPP_FROM`, `ALERT_WHATSAPP_TO` | WhatsApp |
| `EMAILJS_SERVICE_ID`, `EMAILJS_TEMPLATE_ID`, `EMAILJS_PUBLIC_KEY`, `EMAILJS_PRIVATE_KEY`, `ALERT_EMAIL_TO` | Email |
| `SYNAPSE_RPM_<PROVIDER>`, `SYNAPSE_TPM_<PROVIDER>` | Wait before a rate limit is hit |
| `SYNAPSE_RECEIPT_KEY` | Sign receipts |

Runs are stored locally by default, as digests rather than full outputs, for 30 days, with a 256 MB cache. `synapse storage` shows what's held.

## Limits

- Correctness is checked on your tasks, not proven for every input. Without checkers, there's nothing to judge against.
- `verify`, `force`, `replay` and `chaos` run on built-in demo workflows. Real corpora run through `synapse bench` in a repository checkout.
- Replay can't see a server that changes answers under load, so run `synapse audit` first.
- A live run never reuses recordings, so only stubbed runs resume after a crash.
- The semantic cache uses word overlap, not embeddings, and is experimental.
- Adapters refuse what they can't compile safely, such as CrewAI hierarchical crews and LangGraph conditional edges.

## Team

Half a Byte: Aryan Lomte ([Aryan-lomte05](https://github.com/Aryan-lomte05)), Radhesh ([rad117](https://github.com/rad117)), Aditya ([02Aditya2323](https://github.com/02Aditya2323)), Advay Chavan ([advay1608](https://github.com/advay1608)).

## License

MIT.
