Metadata-Version: 2.4
Name: reinc
Version: 0.1.1
Summary: Local-first safety layer for every AI agent on your machine
Project-URL: Homepage, https://github.com/cabernect/reinc
Project-URL: Issues, https://github.com/cabernect/reinc/issues
Author: caber
License: MIT
License-File: LICENSE
Keywords: agents,ai,antigravity,claude,cli,codex,cursor,devin,hooks,safety
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
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 :: Security
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: click>=8.1
Requires-Dist: rich>=13.0
Requires-Dist: textual>=0.50
Requires-Dist: watchfiles>=0.21
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

# Reinc

> Local-first safety layer for AI coding agents. Version 0.1.

> **Status: early alpha.** Five agents are integrated: **Claude Code**, **Codex**, **Cursor**,
> **Devin**, and **Antigravity** — all validated end-to-end against live agents. The pre-hook now
> scans tool **input** (file content being written,
> commands being run) for prompt-injection / secret patterns **before** execution, so writing
> an instruction-override phrase to a file is denied before the file is created — not just
> flagged when it's read back. Three agent-specific notes: **Codex** writes/edits files via
> `apply_patch` (reinc parses the patch to gate it) and has **no native `ask`**, so a warn-tier
> Codex call fails closed to `deny`. **Cursor** is **IDE/cloud-first**: the Cursor CLI
> (`cursor-agent`) fires only a subset of hooks, so there it gates shell commands but can't block
> file writes/edits pre-execution (full blocking works in the IDE/cloud). **Antigravity** uses
> PostInvocation + transcript JSONL reading for post-audit (PostToolUse carries no tool output).
> It's a **guardrail, not a sandbox** ([see below](#not-a-sandbox)) — don't rely on it as your only
> protection. Feedback and issues very welcome.

Reinc sits between your AI coding agents and your machine. Every tool call an agent makes —
reading files, writing code, running shell commands, making network requests — is intercepted
by the agent's own pre-tool hook, scored for risk (0–100), and logged. When a call is risky
enough to need a human, Reinc returns **`ask`** and the agent shows *its own* native approval
prompt — right where you already work. (On agents that can only allow/deny and have no native
`ask`, like Codex, a warn-tier call **fails closed to `deny`** instead.) All data stays on your
machine. No accounts, no servers, no telemetry.

Targets Claude Code, OpenAI Codex, Cursor, Devin (incl. Windsurf), and Google Antigravity. **Today Claude Code,
Codex, Cursor, Devin, and Antigravity are integrated end-to-end** (wire dialect + `reinc register`); a Cline
dialect exists but has no register path yet (see
[`docs/INTEGRATION.md`](docs/INTEGRATION.md)).

Reinc gates tool calls **on your machine**. `reinc register devin` (one global hook at
`~/.config/devin/config.json`) covers the Devin **CLI**, the **Devin Local** agent, and **Windsurf**
(which runs Devin Local after the Cognition acquisition) — they share the same hook contract — so
**Devin Desktop and Windsurf are covered when they run Devin Local**. Policy stays per-project.
Not covered: **Devin Cloud** agents (they run in Cognition's remote sandbox), and the legacy
*Cascade* hooks Windsurf is phasing out (EOL 2026-07-01).

## How it works

Reinc is **not** an MCP server. MCP *adds* tools to an agent; it does not gate the agent's
native tools. Reinc instead wires into each agent's **pre-tool-execution hook** — the only
primitive that can actually deny a call before it runs.

Three layers, each with one job:

- **Hooks enforce.** A tiny, per-call `reinc hook` process parses the agent's tool call,
  scores it, and replies `allow` / `deny` / `ask`. `ask` hands the prompt back to the agent —
  on agents that support it; ask-incapable ones (e.g. Codex) fail closed to `deny`.
- **Config declares.** `.reinc/config.toml` (committed, shared with your team) plus the
  gitignored `.reinc/personal.toml` (your local overrides) are the single source of truth for
  policy. There is no learned or remembered state that changes decisions.
- **The TUI logs.** `reinc monitor` is a read-only dashboard that tails the audit log. It never
  prompts you — your agent does that.

```
  Claude Code                         reinc monitor (read-only)
      │                               ┌─ Reinc ─────────────────┐
      │ PreToolUse hook               │  12:04 claude write_file│
      ▼                               │  src/auth/login.ts   72 │
  reinc hook ──── sqlite ─────────►  │  12:04  → ask           │
      │       ◄── allow/deny/ask ──  └─────────────────────────┘
      ▼
  agent runs the tool, or shows its own prompt (on `ask`), or refuses (on `deny`)
```

No daemon — the hook reads/writes sqlite directly. Each call opens the db, reads recent
history (reconstructing the behavioral scorer's cross-call state), scores, writes the audit
row, and closes. `reinc monitor` is a read-only TUI that polls sqlite every 0.5s.

## Install

reinc is a Python CLI. Every channel installs the same package — pick whichever you like:

```bash
# PyPI (recommended — isolated install)
uv tool install reinc            # or: pipx install reinc

# Homebrew (macOS / Linux) — once the tap is published
brew install cabernect/tap/reinc

# curl — picks uv / pipx / pip for you, installs isolated
curl -fsSL https://raw.githubusercontent.com/cabernect/reinc/main/install.sh | sh
```

> **From source** (latest unreleased):
>
> ```bash
> git clone https://github.com/cabernect/reinc && cd reinc
> uv venv && uv pip install -e .   # or: python -m venv .venv && .venv/bin/pip install -e .
> reinc --version
> ```

## Quick start

```bash
cd your-project/
reinc init                # creates .reinc/config.toml + .reinc/db/
reinc register claude-code # wires reinc into ~/.claude/settings.json hooks
# also available: reinc register codex | cursor | devin | antigravity
```

Add this to your project's `.gitignore`:

```
.reinc/db/
.reinc/personal.toml
```

Commit `.reinc/config.toml` so teammates get the same rules. Keep `.reinc/personal.toml` local —
it holds *your* machine's overrides.

Watch decisions live (optional):

```bash
reinc monitor             # read-only dashboard (polls the sqlite audit db)
```

To undo: `reinc unregister claude-code`.

## Policy

Project policy lives in `.reinc/config.toml`. Rules are `tool:glob` patterns:

```toml
[policy]
mode = "interactive"   # interactive | strict | permissive | headless

[thresholds]
warn_above  = 30
block_above = 60

[never_allow]            # absolute ceiling — never overridden
rules = ["bash:rm -rf /", "write_file:/etc/**", "write_file:~/.ssh/**"]

[allow]                  # auto-allow, just log
rules = ["read_file:src/**", "write_file:src/**", "list_dir:**", "search_files:**"]

[warn]                   # force the agent's approval prompt (`ask`)
rules = ["write_file:src/auth/**", "bash:git push *"]

[block]                  # hard deny
rules = ["write_file:.env*", "write_file:*.pem", "write_file:*.key"]

[paths]                  # tag targets with a sensitivity multiplier
config = { paths = ["*.toml", "*.json"], sensitivity = "high" }
tests  = { paths = ["tests/**", "**/*.test.*"], sensitivity = "low" }
```

### Personal overrides

Adjust policy for just your machine without touching the shared config:

```bash
reinc allow "write_file:scratch/**"   # appends to .reinc/personal.toml [allow]
reinc deny  "bash:curl *"             # appends to .reinc/personal.toml [block]
```

Personal rules are merged on top of `config.toml` at load time.

### Modes

| Mode | Low (≤30) | Medium (31–60) | High (>60) |
|---|---|---|---|
| `interactive` | allow | ask | **deny** |
| `strict` | ask | ask | **deny** |
| `permissive` | allow | allow | ask |
| `headless` | allow | allow | **deny** |

`block_above` (default 60) is honored in `interactive`, `strict`, and `headless` — score > 60 →
deny. `permissive` is the only mode that asks (not denies) on high.

`headless` never emits `ask` — use it in CI where no human is present. On an **ask-incapable
agent** (Codex, Cursor's non-shell events) every `ask` above collapses to `deny`, which shifts
the effective allow/deny cutoff — see [`docs/POLICY.md`](docs/POLICY.md). Full rule syntax, the
precedence ladder, and common recipes (allow-all-except, read-only, lockdown) are there too.

### Precedence

```
never_allow  →  block  →  warn  →  allow  →  risk scorer + thresholds
```

The first matching rule wins. If nothing matches, the risk scorer decides.

## Risk scoring

When no explicit rule matches, Reinc scores the call 0–100 over three layers:

1. **Base score** per tool (`read_file` 8, `edit_file` 20, `write_file` 25, `bash` 35,
   `http_request` 20–55, …).
2. **Sensitivity multiplier** from `[paths]` and built-in critical patterns (`.env*`, `*.pem`,
   `src/auth/**`, `~/.ssh/**`, …): low ×0.5, medium ×1.0, high ×1.5, critical ×2.5.
3. **Behavioral bonus** from the session stream: reconnaissance loop (+20), exfil signature
   (+40), scope creep (+15), repeated probing (+10), cascade delete (+30).
4. **Input scanning bonus** from the pre-hook: the tool's input content (file text being written,
   command being run) is scanned for prompt-injection / secret patterns **before** execution.
   A match adds the scanner bonus (+40 injection, +30 secret) to the score before the band
   lookup — so writing an instruction-override phrase to a file can push 25 → 65 → **deny**,
   blocked before the file is created. Flags are persisted to the audit log and shown in
   `reinc monitor`.

```
score = min(100, round((base × sensitivity + behavior_bonus) × agent_trust_multiplier) + input_scan_bonus)
```

`agent_trust_multiplier` (high ×0.7 / medium ×1.0 / low ×1.3) scales the score for more- or
less-trusted agents. It never overrides an explicit allow/block/warn rule.

## CLI reference

```bash
reinc init                  # create .reinc/ in the current project
reinc register <agent>      # wire an agent's hooks to reinc (claude-code | codex | cursor | devin | antigravity)
reinc unregister <agent>    # remove reinc's hooks
reinc monitor               # read-only logging dashboard (polls sqlite)
reinc allow "<pattern>"     # append a personal allow rule
reinc deny  "<pattern>"     # append a personal block rule
reinc hook --agent <name>   # internal: score one tool call from stdin (called by hooks)
```

## Not a sandbox

Reinc is a **guardrail, not a container.** Hooks run inside the agent's own trust domain, and
documented bypasses of agent approval gates exist. Reinc's value is catching mistakes, drift,
and prompt-injection accidents with an explainable, unified policy — not airtight containment.
A real OS-level sandbox floor is an optional future hardening layer. See
[`docs/THREAT_MODEL.md`](docs/THREAT_MODEL.md) for exactly what Reinc does and does not defend
against (including Reinc's own attack surface), and
[`docs/INTEGRATION.md`](docs/INTEGRATION.md) for the architecture and per-agent capability matrix.
