Metadata-Version: 2.4
Name: company-ai
Version: 0.2.2
Summary: Internal Claude gateway control layer and developer CLI
Author: Company AI
License-Expression: LicenseRef-Proprietary
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: requests==2.32.5
Requires-Dist: keyring==25.6.0

# Claude Control Layer

FastAPI control plane for Claude/LiteLLM access with users, roles, teams, runtime policy settings, quota metadata, usage analytics, alerts, and admin APIs.

Claude Code no longer points directly at the FastAPI app for Anthropic-compatible transport. Claude Code points at LiteLLM, while this app manages the surrounding control-plane data and can create LiteLLM virtual keys for users.

## Features

- Role-based model enforcement for `admin`, `engineer`, and `worker`
- Daily token quota checks per user
- Full usage logging in Postgres
- Admin analytics for overview, users, models, trends, and estimated cost
- Token-based admin authentication with login
- LiteLLM proxy service for Claude Code transport
- LiteLLM virtual-key creation from admin-managed users, roles, and teams
- Redis client wiring for future rate-limiting or caching work
- Dockerized local development

## Project layout

```text
app/
  core/
  models/
  routes/
  schemas/
  services/
docker/
migrations/
admin-dashboard/
```

## Run locally with Docker

```bash
docker-compose up --build
```

The API will be available at `http://localhost:8000`.
LiteLLM will be available at `http://localhost:4000`.

## API endpoints

- `POST /chat`
- `POST /auth/login`
- `POST /auth/claude-code-token`
- `POST /v1/messages`
- `POST /v1/messages/count_tokens`
- `GET /health`
- `GET /auth/me`
- `GET /admin/overview`
- `GET /admin/users`
- `GET /admin/trends`
- `GET /admin/models`
- `GET /admin/cost`

`POST /chat`, `POST /v1/messages`, and `POST /v1/messages/count_tokens` are legacy FastAPI transport endpoints and are disabled by default. Set `ENABLE_LEGACY_CLAUDE_TRANSPORT=true` only for a temporary migration window.

`POST /auth/claude-code-token` is deprecated and returns `410 Gone`. Claude Code should use a LiteLLM virtual key instead.

Admins can create a LiteLLM virtual key for an app user with:

```text
POST /admin/users/{user_id}/litellm-key
```

## Admin auth

Admin routes accept bearer tokens returned by `POST /auth/login`. The dashboard now requires login before loading `/` or `/settings`.

On a fresh Postgres volume, Docker seeds an admin user automatically:

```text
username/id: anase
password: numnum2001
role: admin
```

Use a strong `AUTH_SECRET` in `.env` for production deployments.

For local dashboard access, keep `ALLOWED_ORIGINS` aligned with the frontend URL. By default it allows:

```text
http://localhost:3000
http://127.0.0.1:3000
```

## Example chat request

```json
{
  "user_id": "u_123",
  "model": "claude-sonnet-4-6",
  "max_tokens": 1024,
  "messages": [
    {
      "role": "user",
      "content": "Summarize the latest deployment notes."
    }
  ]
}
```

## LiteLLM Transport

LiteLLM runs as a separate service in Docker Compose and listens on port `4000`.

The local LiteLLM config is:

```text
litellm/config.yaml
```

It uses:

- Postgres-backed LiteLLM key management through `DATABASE_URL`
- `LITELLM_MASTER_KEY` for admin/control-plane calls
- `x-litellm-api-key` as the virtual-key header
- `claude-code-sonnet` as the local default model name

For local development, configure these in `.env`:

```text
LITELLM_PROXY_URL=http://localhost:4000
LITELLM_INTERNAL_URL=http://litellm:4000
LITELLM_MASTER_KEY=sk-local-litellm-master-key
LITELLM_DEFAULT_MODEL=claude-code-sonnet
ENABLE_LEGACY_CLAUDE_TRANSPORT=false
```

## Developer CLI

The `company-ai` CLI lets developers configure Claude Code to use LiteLLM while the FastAPI app remains the admin/control plane.

Install from PyPI:

```bash
pip install --upgrade company-ai
```

Install the Python requirements first:

```bash
pip install -r requirements.txt
```

For a real `company-ai` command on PATH, install the local package:

```bash
pip install -e .
```

Check the installed version:

```bash
company-ai --version
```

Log in once:

```bash
company-ai login --gateway http://localhost:8000
```

The CLI prompts for email and password, calls `POST /auth/login`, stores the app session token in the OS keychain through `keyring`, and saves non-secret config in:

```text
~/.config/company-ai/config.json
```

Configure Claude Code:

```bash
company-ai setup-claude --litellm-url http://localhost:4000 --litellm-key sk-your-user-virtual-key --model claude-code-sonnet
```

This safely updates:

```text
~/.claude/settings.json
```

with:

```json
{
  "env": {
    "ANTHROPIC_BASE_URL": "http://localhost:4000",
    "ANTHROPIC_CUSTOM_HEADERS": "x-litellm-api-key: Bearer sk-your-user-virtual-key",
    "ANTHROPIC_MODEL": "claude-code-sonnet"
  }
}
```

Claude Code should remain logged in with Claude subscription auth client-side. The LiteLLM virtual key is sent separately in `ANTHROPIC_CUSTOM_HEADERS`.

## Releasing the CLI

Release notes and tag/publish steps live in `RELEASING.md`.

## Claude Subscription Limit Breaker

Claude Code traffic is protected by a global subscription-limit circuit breaker. This is separate from app quotas and model policy. It represents the real upstream Claude subscription lockout, such as the Claude Max 5-hour plan limit.

The flow is:

1. LiteLLM forwards Claude Code traffic upstream.
2. If the upstream provider returns a subscription-limit/reset error, the LiteLLM callback reports the sanitized error to FastAPI at `POST /internal/litellm/subscription-limit`.
3. FastAPI stores an active block in `system_runtime_blocks` with the reason `claude_subscription_limit_reached`, the detected time, sanitized upstream message, and a parsed UTC reset time when available.
4. The LiteLLM policy check at `POST /internal/litellm/policy` checks this block before local quotas, model policy, and request guardrails.
5. While the block is active, new Claude requests are rejected before any upstream call with a fatal terminal message that includes the reset time when known.
6. The Alerts page shows a critical alert titled `Team reached Claude subscription limit`.
7. If `reset_at` is known, the block clears automatically after that time on the next policy/admin check. If the reset time is unknown, an admin can clear it manually after verifying Claude access has recovered.

Admin endpoints:

```text
GET /admin/system/subscription-limit-state
POST /admin/system/subscription-limit-state/clear
POST /admin/system/subscription-limit-state/probe
```

The probe endpoint reports the current state. In Claude subscription mode the server cannot perform a real upstream probe without client-side Claude Code subscription credentials, so unknown-reset blocks should be cleared manually after a user confirms Claude works again.

You can also provide setup values through environment variables:

```text
COMPANY_AI_LITELLM_URL=http://localhost:4000
COMPANY_AI_LITELLM_KEY=sk-your-user-virtual-key
COMPANY_AI_LITELLM_MODEL=claude-code-sonnet
```

After setup, run:

```bash
claude
```

Then verify with `/status`.

To remove the stored app session:

```bash
company-ai logout
```

## Dashboard

A minimal Next.js dashboard is included under `admin-dashboard/`.

```bash
cd admin-dashboard
npm install
npm run dev
```
