# oAI-Web - Personal AI Agent

A secure, self-hosted personal AI agent powered by OpenRouter, Anthropic and OpenAI. Handles calendar, email, files, web research, and Telegram - controlled by you, running on your own hardware.

## Features

- **Chat interface** - conversational UI via browser, with model selector
- **CalDAV** - read and write calendar events
- **Email** - read inbox, send replies (whitelist-managed recipients)
- **Filesystem** - read/write files in declared sandbox directories
- **Web access** - tiered: whitelisted domains always allowed, others on request
- **Push notifications** - Pushover for iOS/Android
- **Telegram** - send and receive messages via your own bot
- **Scheduled tasks** - cron-based autonomous tasks with declared permission scopes
- **Agents** - goal-oriented runs with model selection and full run history
- **Audit log** - every tool call logged, append-only
- **Multi-user** - each user has their own credentials and settings

oAI-Web also has an extensive built in help function. This makes it easy for both admins and normal useres to learn and use oAI-Web in the best way possible. 

---

## Requirements

- Docker and Docker Compose
- An API key from [Anthropic](https://console.anthropic.com) and/or [OpenRouter](https://openrouter.ai) and/or [OpenAI](https://openai.com)
- A PostgreSQL-compatible host (included in the compose file)

---

## Installation

### 1. Get the files

Download or copy these files into a directory on your server:

- `docker-compose.example.yml` - rename to `docker-compose.yml`
- `.env.example` - rename to `.env`
- `SOUL.md.example` - rename to `SOUL.md`
- `USER.md.example` - rename to `USER.md`

```bash
cp docker-compose.example.yml docker-compose.yml
cp .env.example .env
cp SOUL.md.example SOUL.md
cp USER.md.example USER.md
```

### 2. Create the data directory

```bash
mkdir -p data
```

### 3. Configure the environment

Edit `.env` - see the [Environment Variables](#environment-variables) section below.

### 4. Pull and start

```bash
docker compose pull
docker compose up -d
```

Open `http://<your-server-ip>:8080` in your browser.

On first run you will be taken through a short setup wizard to create your admin account.

---

## Environment Variables

Open `.env` and fill in the values. Required fields are marked with `*`.

### AI Provider

```env
# Which provider to use as default: anthropic | openrouter | openai
DEFAULT_PROVIDER=anthropic

# Override the default model (leave empty to use the provider's default)
# DEFAULT_MODEL=claude-sonnet-4-6

# Model pre-selected in the chat UI (leave empty to use provider default)
# DEFAULT_CHAT_MODEL=claude-sonnet-4-6
```

Your actual API keys are **not** set here - they are entered via the web UI under **Settings - Credentials** and stored encrypted in the database.

---

### Security *

```env
# Master password for the encrypted credential store.
# All your API keys, passwords, and secrets are encrypted with this.
# Choose a strong passphrase and keep it safe - if lost, credentials cannot be recovered.
DB_MASTER_PASSWORD=change-me-to-a-strong-passphrase
```

---

### Server

```env
# Port the web interface listens on (default: 8080)
PORT=8080

# Timezone for display - dates are stored internally as UTC
TIMEZONE=Europe/Oslo
```

---

### Agent Limits

```env
# Maximum number of tool calls per agent run
MAX_TOOL_CALLS=20

# Maximum number of autonomous (scheduled/agent) runs per hour
MAX_AUTONOMOUS_RUNS_PER_HOUR=10
```

Both values can also be changed live from **Settings - General** without restarting.

---

### Database *

```env
# Main application database
AIDE_DB_URL=postgresql://aide:change-me@postgres:5432/aide

# 2nd Brain database password (pgvector)
BRAIN_DB_PASSWORD=change-me-to-a-strong-passphrase

# Brain connection string - defaults to the bundled postgres service
BRAIN_DB_URL=postgresql://brain:${BRAIN_DB_PASSWORD}@postgres:5432/brain

# Access key for the Brain MCP endpoint (generate with: openssl rand -hex 32)
BRAIN_MCP_KEY=
```

Change the `change-me` passwords in `AIDE_DB_URL` and `BRAIN_DB_PASSWORD` to something strong. They must match - if you change `BRAIN_DB_PASSWORD`, the same value is substituted into `BRAIN_DB_URL` automatically.

---

## Personalising the Agent

### SOUL.md - Agent identity and personality

`SOUL.md` defines who your agent is. The name is extracted automatically from the first line matching `You are **Name**`.

Key sections to edit:

**Name** - change `Jarvis` to whatever you want your agent to be called:
```markdown
You are **Jarvis**, a personal AI assistant...
```

**Character** - describe how you want the agent to behave. Be specific. Examples:
- "You are concise and avoid unnecessary commentary."
- "You are proactive - if you notice something relevant while completing a task, mention it briefly."
- "You never use bullet points unless explicitly asked."

**Values** - define what the agent should prioritise:
- Privacy, minimal footprint, and transparency are good defaults.
- Add domain-specific values if relevant (e.g. "always prefer open-source tools when suggesting options").

**Language** - specify language behaviour explicitly:
- "Always respond in the same language the user wrote in."
- "Default to Norwegian unless the message is in another language."

**Communication style** - tune the tone:
- Formal vs. casual, verbose vs. terse, proactive vs. reactive.
- You can ban specific phrases: "Never start a response with 'Certainly!' or 'Of course!'."

The file is mounted read-only into the container. Changes take effect on the next `docker compose restart`.

---

### USER.md - Context about you

`USER.md` gives the agent background knowledge about you. It is injected into every system prompt, so keep it factual and relevant - not a biography.

**Identity** - name, location, timezone. These help the agent interpret time references and address you correctly.

```markdown
## Identity

- **Name**: Jane
- **Location**: Oslo, Norway
- **Timezone**: Europe/Oslo
```

**Language preferences** - if you want to override SOUL.md language rules for your specific case:

```markdown
## Language

- Respond in the exact language the user's message is written in.
- Do not assume Norwegian because of my location.
```

**Professional context** - role and responsibilities the agent should be aware of:

```markdown
## Context and background

- Works as a software architect
- Primarily works with Python and Kubernetes
- Manages a small team of three developers
```

**People** - names and relationships. Helps the agent interpret messages like "send this to my manager":

```markdown
## People

- [Alice Smith] - Manager
- [Bob Jones] - Colleague, backend team
- [Sara Lee] - Partner
```

**Recurring tasks and routines** - anything time-sensitive the agent should know about:

```markdown
## Recurring tasks and routines

- Weekly team standup every Monday at 09:00
- Monthly report due on the last Friday of each month
```

**Hobbies and interests** - optional, but helps the agent contextualise requests:

```markdown
## Hobbies and Interests

- Photography
- Self-hosting and home lab
- Cycling in summer
```

The file is mounted read-only into the container. Changes take effect on the next `docker compose restart`.

---

## First Run - Settings

After the setup wizard, go to **Settings** to configure your services.

### Credentials (admin only)

Add credentials for the services you use. Common keys:

| Key | Example | Used by |
|-----|---------|---------|
| `anthropic_api_key` | `sk-ant-...` | Claude (Anthropic) |
| `openrouter_api_key` | `sk-or-...` | OpenRouter models |
| `mailcow_host` | `mail.yourdomain.com` | CalDAV, Email |
| `mailcow_username` | `you@yourdomain.com` | CalDAV, Email |
| `mailcow_password` | your IMAP password | CalDAV, Email |
| `caldav_calendar_name` | `personal` | CalDAV |
| `pushover_app_token` | from Pushover dashboard | Push notifications |
| `telegram_bot_token` | from @BotFather | Telegram |

### Whitelists

- **Email whitelist** - addresses the agent is allowed to send email to
- **Web whitelist** - domains always accessible to the agent (Tier 1)
- **Filesystem sandbox** - directories the agent is allowed to read/write

---

## Updating

```bash
docker compose pull
docker compose up -d
```

---

## Pages

| URL | Description |
|-----|-------------|
| `/` | Chat - send messages, select model, view tool activity |
| `/tasks` | Scheduled tasks - cron-based autonomous tasks |
| `/agents` | Agents - goal-oriented runs with model selection and run history |
| `/audit` | Audit log - filterable view of every tool call |
| `/settings` | Credentials, whitelists, agent config, Telegram, and more |


## License

oAI is free software licensed under the **GNU Affero General Public License v3.0 (AGPL-3.0)**.

This means you are free to use, study, modify, and distribute oAI, but any modified version you run as a network service must also be made available as free software under the same license.

See [LICENSE](LICENSE) for the full license text, or visit [gnu.org/licenses/agpl-3.0](https://www.gnu.org/licenses/agpl-3.0.html).

## Author

**Rune Olsen**

- Website: https://jarvis.pm
- Blog: [https://blog.rune.pm](https://blog.rune.pm)
- Gitlab.pm: [@rune](https://gitlab.pm/rune)

## Contributing

Contributions are welcome!

---

**⭐ Star this project if you find it useful!**

**🐛 Found a bug?** [Open an issue](https://gitlab.pm/rune/oai-web/issues/new)