# Settings Configuration

Settings are stored in `~/.forge/data/settings.yaml`. Configure via the web UI (Settings button in top-right menu) or edit YAML directly.

## All Settings Fields

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `projectRoots` | string[] | `[]` | Directories containing your projects (e.g. `~/Projects`) |
| `docRoots` | string[] | `[]` | Markdown/Obsidian vault directories |
| `claudePath` | string | `""` | Path to claude binary (auto-detected if empty) |
| `claudeHome` | string | `""` | Claude Code home directory (default: `~/.claude`) |
| `telegramBotToken` | string | `""` | Telegram Bot API token (encrypted) |
| `telegramChatId` | string | `""` | Telegram chat ID (comma-separated for multiple users) |
| `notifyOnComplete` | boolean | `true` | Telegram notification on task completion |
| `notifyOnFailure` | boolean | `true` | Telegram notification on task failure |
| `tunnelAutoStart` | boolean | `false` | Auto-start Cloudflare Tunnel on server startup |
| `telegramTunnelPassword` | string | `""` | Admin password for login + tunnel + secrets (encrypted) |
| `taskModel` | string | `"default"` | Model for background tasks |
| `pipelineModel` | string | `"default"` | Model for pipeline workflows |
| `telegramModel` | string | `"sonnet"` | Model for Telegram AI features |
| `defaultAgent` | string | `"claude"` | Default agent for tasks and terminal |
| `telegramAgent` | string | `""` | Agent for Telegram task execution |
| `docsAgent` | string | `""` | Agent for documentation queries |
| `skipPermissions` | boolean | `false` | Add `--dangerously-skip-permissions` to claude invocations |
| `manageClaudeConfig` | boolean | `true` | When `false`, Forge will not modify `~/.claude/` or project `.claude/` files (skills, Stop hook, permissions, profile env/model) |
| `notificationRetentionDays` | number | `30` | Auto-cleanup notifications older than N days |
| `skillsRepoUrl` | string | forge-skills URL | GitHub raw URL for skills registry |
| `displayName` | string | `"Forge"` | Display name shown in header |
| `displayEmail` | string | `""` | User email |
| `favoriteProjects` | string[] | `[]` | Starred project paths |
| `obsidianVault` | string | `""` | Path to Obsidian vault |

## Agents

Forge auto-detects installed CLI agents (Claude Code, Codex, Aider). You can also add custom agents manually.

### Agent Fields

Each agent entry in `settings.agents` supports:

| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Display name |
| `path` | string | Path to CLI binary |
| `enabled` | boolean | Whether this agent is available |
| `cliType` | string | CLI tool type: `claude-code`, `codex`, `aider`, `generic` |
| `taskFlags` | string | Flags for headless task execution (e.g. `-p --verbose`) |
| `resumeFlag` | string | Flag to resume sessions (e.g. `-c` for claude) |
| `outputFormat` | string | Output format: `stream-json`, `text` |
| `skipPermissionsFlag` | string | Flag to skip permissions (e.g. `--dangerously-skip-permissions`) |
| `requiresTTY` | boolean | Whether agent needs a PTY (true for codex) |
| `models` | object | Model overrides per context: `terminal`, `task`, `telegram`, `help`, `mobile` |
| `profile` | string | Linked profile ID — applies that profile's env/model when launching |

### CLI Type

The `cliType` field determines how Forge interacts with the agent:

| CLI Type | Session Support | Resume | Skip Permissions |
|----------|----------------|--------|------------------|
| `claude-code` | Yes (session files) | `-c` / `--resume <id>` | `--dangerously-skip-permissions` |
| `codex` | No | — | `--dangerously-bypass-approvals-and-sandbox` |
| `aider` | No | — | `--yes` |
| `generic` | No | — | — |

### Example YAML

```yaml
agents:
  claude:
    name: Claude Code
    path: /usr/local/bin/claude
    enabled: true
    cliType: claude-code
    skipPermissionsFlag: --dangerously-skip-permissions
  codex:
    name: OpenAI Codex
    path: codex
    enabled: true
    cliType: codex
    requiresTTY: true
    skipPermissionsFlag: --dangerously-bypass-approvals-and-sandbox
```

## Agent Profiles

Profiles are reusable configurations that extend a base agent with custom environment variables, model overrides, and CLI settings. Any smith or terminal session can use a profile.

### Profile Fields

| Field | Type | Description |
|-------|------|-------------|
| `base` | string | Base agent ID (e.g. `claude`, `codex`) — makes this entry a profile |
| `name` | string | Display name |
| `model` | string | Model override (passed via `--model` flag) |
| `env` | object | Environment variables injected when launching |
| `cliType` | string | Override CLI type (inherits from base if not set) |
| `enabled` | boolean | Whether this profile is available |

### Example: Custom API Endpoint Profile

```yaml
agents:
  forge-k2:
    base: claude
    name: Forge K2
    model: forge-k2
    env:
      ANTHROPIC_AUTH_TOKEN: sk-xxx
      ANTHROPIC_BASE_URL: http://my-server:7001/
      ANTHROPIC_SMALL_FAST_MODEL: forge-k2
      CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "true"
      DISABLE_TELEMETRY: "true"
```

### Example: Model Override Profile

```yaml
agents:
  claude-opus:
    base: claude
    name: Claude Opus
    model: claude-opus-4-6
  claude-sonnet:
    base: claude
    name: Claude Sonnet
    model: claude-sonnet-4-6
```

### How Profiles Work

1. A profile inherits all capabilities from its base agent (binary path, session support, resume flags)
2. Environment variables from `env` are exported before launching the CLI
3. The `model` field is passed as `--model <value>` flag (claude-code) or via env
4. Profiles appear in agent selection dropdowns alongside base agents

### Linking a Profile to an Agent

In the agent configuration, set the `profile` field to link a profile:

```yaml
agents:
  claude:
    profile: forge-k2    # Claude will use forge-k2's env/model when launched
```

This applies the profile's environment variables and model override whenever that agent is launched in a terminal.

## API agent profiles

API access (used by API-backend smiths and the chat backend) is configured
as agent profiles with `type: api`. The same profile is reused everywhere
— no separate provider/key duplication.

```yaml
agents:
  my-litellm:
    type: api
    name: My LiteLLM
    provider: litellm            # display label
    model: claude-sonnet-4-6
    apiKey: sk-...               # encrypted on save
    baseUrl: http://127.0.0.1:4000/v1   # LiteLLM / Azure / self-hosted proxy

  direct-anthropic:
    type: api
    name: Anthropic Direct
    provider: anthropic
    model: claude-haiku-4-5-20251001
    apiKey: sk-ant-...

chatAgent: my-litellm             # which profile Forge's chat backend uses
```

The chat backend (extension chat, `forge chat`, Telegram `/chat`) picks
`settings.chatAgent` by default; a session can override via
`Session.provider = <profile-id>`.

Provider → adapter mapping for chat:
- `provider: anthropic` (or `claude`) → Anthropic Messages API protocol
- everything else → OpenAI-compatible protocol (LiteLLM, Grok, Google via
  LiteLLM, OpenAI itself, Azure)

`baseUrl` falls back to `env.ANTHROPIC_BASE_URL` / `env.OPENAI_BASE_URL` /
`env.OPENAI_API_BASE` if not set directly. `apiKey` falls back to
`env.ANTHROPIC_API_KEY` / `env.ANTHROPIC_AUTH_TOKEN` /
`env.OPENAI_API_KEY`. This makes a single profile usable both by a CLI
(reads `env`) and by chat (reads the top-level field).

## Admin Password

- Set on first launch (CLI prompt)
- Required for: login, tunnel start, secret changes, Telegram commands
- Reset: `forge --reset-password`

## Encrypted Fields

`telegramBotToken` and `telegramTunnelPassword` are encrypted with AES-256-GCM. Agent profile `apiKey` fields are also encrypted. Enterprise marketplace keys (see below) live in `<dataDir>/.enterprise-keys.json` and are encrypted with the same key. The encryption key is stored at `~/.forge/data/.encrypt-key`.

## Marketplace Providers (enterprise keys)

Forge's connector + workflow marketplaces are layered. The default `forge-connectors` / `forge-workflow` repos are everyone's baseline; on top of those you can register one or more **enterprise repos** that override matching ids with company-specific versions and add private ones. This is opt-in — without any keys, you see only the public catalog.

### Key formats

- **Short** — `<tenant_id>:<github_pat>` (e.g. `fortinet:github_pat_xxxxx`). The tenant short code is resolved to a known enterprise repo URL via `lib/enterprise-known.ts`.
- **Long** — `<github_pat>@<repo_url>` (e.g. `github_pat_xxxxx@github.com/myorg/forge-enterprise-agent-foo`). Escape hatch for tenants not in the known list.

The PAT must be a GitHub **Fine-grained Personal Access Token** scoped to the enterprise repo with `Contents: Read`.

### How to register

Three equivalent paths — pick whichever fits the moment:

```bash
# A) at install time
./install.sh --enterprise-key=fortinet:github_pat_xxxxx

# B) one-shot from the CLI (persist + exit, no server start)
forge --add-enterprise-key --enterprise-key=fortinet:github_pat_xxxxx

# C) inside Forge chat — paste the key, the assistant calls add_enterprise_key
```

After registration:

- The connector + workflow marketplaces auto-sync once so the new source appears immediately.
- The Marketplace UI shows a `🔒 <tenant>` badge on every connector/pipeline sourced from this repo; the detail pane's "Sources" section lists the winning source plus any lower-priority sources that were outranked.
- The Dashboard top nav shows `🔒 <tenant>` so you always know which enterprise overlays are active.

### Manage via Settings → Marketplace Providers

The Settings modal section lists every configured source with its priority + masked PAT preview. Add a new key, remove an existing one, or see what's loaded. Removing a source keeps already-installed connectors/workflows on disk (so you don't lose work) — they just stop receiving updates from that source.

### Priority rules

- Sources are ordered by registration sequence; the first key added wins on conflict.
- For each id (e.g. `mantis`), the highest-priority source providing it is "in use"; lower sources land in `hidden_sources` (visible in the marketplace detail page).
- A `connector-config-template.json` (onboarding wizard pre-fills) is also resolved across sources — user-uploaded at `<dataDir>/config-template.json` first, then enterprise sources by priority, then public, then the Forge-bundled fallback.

### What stays out of public

Fortinet-internal connectors (`nac`, `fortincm`, `tp`, `scap`, `pmdb`), Fortinet-flavored pipelines (`fortinet-*`), and the Fortinet wizard template live only in the private `forge-enterprise-agent-fortinet` repo. Public `forge-connectors` keeps generic versions of `gitlab` / `mantis` / `blackduck` etc. with empty `base_url` defaults.

## Settings UI

The Settings modal has these sections:

| Section | What it configures |
|---------|-------------------|
| **Project Roots** | Directories to scan for projects |
| **Document Roots** | Markdown/Obsidian vault paths |
| **Agents** | Detected CLI agents + configuration |
| **Profiles** | Agent profiles (CLI + API) — API profiles also power Forge chat |
| **Marketplace Providers** | Enterprise marketplace keys — add/remove tenants whose private connector + pipeline + wizard repos overlay on top of public |
| **Memory (Temper)** | Long-term memory backend for the chat agent. When Temper URL+key are blank, chat falls back to a local SQLite store with the same block/episode tools (keyword search only — no semantic/graph search). Chat summaries are stored as ONE Temper document per chat (`chats/<session>.md`, overwritten with the latest; local backend stores them as `doc:*` blocks); extracted facts go to episodes only. Duplicate / low-quality writes are rejected server-side and never retried. |
| **Chat backend** | Pick the default API profile for chat (extension / CLI / Telegram) |
| **Telegram** | Bot token, chat ID, notification toggles |
| **Display** | Name, email |
| **Other** | Skip permissions, skills repo URL, notification retention |
