Metadata-Version: 2.4
Name: ersan
Version: 0.6.0
Summary: Open-source AI agent for Microsoft 365.
Author-email: Ersan Bilik <ersanbilik@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: ai,cli,microsoft-365,privacy
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Requires-Python: >=3.10
Requires-Dist: anthropic>=0.40
Requires-Dist: pydantic-ai>=1.73
Requires-Dist: pydantic-settings>=2.5
Requires-Dist: pyyaml>=6.0
Requires-Dist: structlog>=24.1
Provides-Extra: repl
Requires-Dist: prompt-toolkit>=3.0.50; extra == 'repl'
Description-Content-Type: text/markdown

```
 ███████╗██████╗ ███████╗ █████╗ ███╗   ██╗
 ██╔════╝██╔══██╗██╔════╝██╔══██╗████╗  ██║
 █████╗  ██████╔╝███████╗███████║██╔██╗ ██║
 ██╔══╝  ██╔══██╗╚════██║██╔══██║██║╚██╗██║
 ███████╗██║  ██║███████║██║  ██║██║ ╚████║
 ╚══════╝╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═╝  ╚═══╝
```
> **Your office. Your rules. Your AI. ...and you, amplified.**

Open-source AI agent for Microsoft 365. Apache 2.0. Runs on your laptop
against your own tenant. No data leaves unless you tell it to.

---

## Why ersan

If you use Microsoft 365 and want an AI agent that:

- doesn't ship your inbox to a third-party SaaS,
- gates every action through a policy you can read,
- redacts PII and credentials from outbound text,
- ships a working CLI in seconds via `pip install`,
- is bilingual out of the box (English + Turkish); community translations welcome — see [docs/i18n.md](docs/i18n.md),

then ersan is for you.

## Architecture

ersan is **the gate** (owns the user relationship), not **infrastructure**
(consumed by other agents). Capabilities load as **skills**, packaged into
**plugins**.

Three pillars:

- **Core**: pydantic-ai Agent runtime, CLI, REPL
- **Policy**: trust tiers (`ask_first`, `do_and_tell`, `do_it`) gating every tool call
- **Shield**: PII / credential redaction on outbound text + ReDoS-safe regex
  compilation, audit-log SHA-256 hash chain, and per-run policy isolation
  (defense-in-depth landed in v0.5.0; see [SECURITY.md](SECURITY.md))

In the current runtime, ersan's core is `pydantic_ai.Agent`. Tool selection
is LLM-driven from natural-language prompts, `ersan.policy` enforces
tier-based gating via `PolicyCapability.wrap_tool_execute()`, and
`ersan.shield` enforces pattern-based blocking plus redaction via
`ShieldHook` registered on the `tool:pre` event of
`ersan.hooks.HookRegistry`, fired by `HookBridgeCapability`.

The ersan runtime ships **no bundled M365 toolset yet** — Microsoft Graph
OAuth via MSAL and the Outlook inbox skills are scheduled for a future
release (US-007). Today the CLI exposes the bare Agent runtime: bring
your own toolset (see [docs/skills.md](docs/skills.md)) or wait for
the bundled Inbox MVP.

## Privacy

- **No telemetry.** Zero phone-home.
- **No third-party LLM calls** unless your config calls them. Structurally
  enforced — local-provider client construction is covered by
  `tests/integration/test_local_provider_no_network.py`, which proves the
  provider factories make zero outbound requests during construction.
- **LLM credentials stay local.** API keys live in `ERSAN_LLM_API_KEY`
  (your env), never written to disk by ersan, never logged, redacted as
  `***` in `ersan config` output and JSON repr (via
  `pydantic.SecretStr`). M365 OAuth tokens are NOT yet stored — the
  MSAL device-code flow lands with US-007.
- **Audit-log to your own sink** (`~/.ersan/audit.log`). Every entry
  carries a SHA-256 `prev_hash` (v0.5.0) so tampering is detectable
  via `ersan.policy.audit.verify_audit_chain`.

## Platform support

ersan is platform-agnostic by construction (per Constitution §Cross-platform invariants).
Every PR runs against:

- **Per PR (6 jobs)**: `ubuntu-latest` × Python 3.10 / 3.11 / 3.12 / 3.13;
  `windows-latest` × Python 3.13; `macos-latest` × Python 3.13.
- **Weekly cron (12 jobs)**: full cartesian — every supported OS × every
  supported Python version.
- **On every release tag (6 jobs)**: smoke-install matrix —
  `{ubuntu, windows, macos} × {Python 3.10, 3.13}` runs `pip install`
  against the freshly built wheel before it reaches PyPI via Trusted
  Publishing with Sigstore PEP 740 attestations.

A wheel does not reach PyPI until the smoke-install matrix passes on all
three operating systems.

## Roadmap

| Version | Status | Shipped |
|---|---|---|
| **v0.1.x** | ✅ released | Architecture-complete: foundations + eval harness + skill loader |
| **v0.2.x** | ✅ released | Model Provider Abstraction — `ersan.providers`, local-first Ollama config, Anthropic config, privacy-invariant provider tests |
| **v0.3.0** | ✅ released | Constitutional pillars — bundled slim port of `ersan.policy` + `ersan.shield`, wired into the loader with the default retail `ask_first` policy and `~/.ersan/audit.log` audit path |
| **v0.4.0** | ✅ released | Agent runtime adoption — `pydantic_ai.Agent`, `PolicyCapability`, `HookBridgeCapability`, slim REPL + one-shot CLI (US-006) |
| **v0.5.0** | ✅ released | Env-first config (`pydantic-settings` + Catwalk-style provider registry, US-010) + defense-in-depth security primitives (5 review findings, see [SECURITY.md](SECURITY.md)) |
| **v0.6.0** | ✅ released | Bilingual i18n out of the box — `ersan.i18n` with English + Turkish locales, `ERSAN_LANG` env var, packaged via `importlib.resources` (US-008). Adds `structlog` as a runtime dep (first adopter; repo-wide migration tracked as US-011) |

| Version | Status | Goal |
|---|---|---|
| **v0.x — next** | planned | **Inbox MVP** — Microsoft Graph OAuth via MSAL device-code flow, `~/.ersan/tokens.json` storage, first bundled Outlook toolset (US-007) |
| **v0.x — later** | planned | OpenTelemetry runtime instrumentation (US-009); repo-wide `structlog` adoption (US-011); OPA-policy evaluation (US-012) |

## Configuration

ersan's runtime config is **env-first** — the source of truth is
`ersan.settings.LLMSettings`. Every config field maps to one
`ERSAN_LLM_*` env var.

Local Ollama example:

```bash
export ERSAN_LLM_PROVIDER=ollama
export ERSAN_LLM_MODEL=llama3
export ERSAN_LLM_BASE_URL=http://localhost:11434/v1
```

Anthropic example:

```bash
export ERSAN_LLM_PROVIDER=anthropic
export ERSAN_LLM_MODEL=claude-3-5-sonnet-latest
export ERSAN_LLM_API_KEY=$ANTHROPIC_API_KEY
```

Run `ersan config` to see what the runtime resolved from your env (the
API key is masked as `"***"`). Run `ersan config --schema` to print the
JSON Schema. See [docs/configuration.md](docs/configuration.md) for the
full env surface.

## How ersan is built

ersan is maintained by Ersan Bilik with AI coding assistants coordinated
through GitHub Spec-Kit and a model-pinned multi-agent dev cycle (D-019).
Every release ships through the same flow: spec → plan → tasks →
implement → 2-way red-team review → fix → merge → architect-owned
sole-truth gate → release.

## Get involved

- 🐛 [Issues](https://github.com/ersan-ai/ersan/issues)
- 📜 [Constitution](CONSTITUTION.md) — what ersan is and isn't
- 🤝 [Contributing](CONTRIBUTING.md)
- 🔒 [Security disclosure](SECURITY.md)
- 📜 [Code of Conduct](CODE_OF_CONDUCT.md)

## License

Apache 2.0. See [LICENSE](LICENSE).

Built by [Ersan Bilik](https://github.com/bilersan).
