> For the complete documentation index, see [llms.txt](https://skyforgeai.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://skyforgeai.gitbook.io/docs/reference/configuration.md).

# Configuration

***

## Config File

`skyforge.jsonc` is picked up automatically when you run `skyforge`. SkyForge searches in this order:

| Location                                              | When to use                                     |
| ----------------------------------------------------- | ----------------------------------------------- |
| `./skyforge.jsonc`                                    | Current directory — per-project (all platforms) |
| `~/skyforge.jsonc`                                    | Home directory — personal global (macOS/Linux)  |
| `~/.config/skyforge/skyforge.jsonc`                   | XDG config dir — global (macOS/Linux)           |
| `C:\Users\<username>\.config\skyforge\skyforge.jsonc` | Global config (Windows)                         |

**Tip:** Start with `~/skyforge.jsonc` so it works from any directory, then override per-project as needed.

***

> **Connecting a provider from the UI:** see [AI Providers](/docs/connect/ai-providers.md). This section covers writing provider config by hand. **ServiceNow auth:** see [Connecting to ServiceNow](/docs/connect/servicenow-connection.md). **Run modes, ports, logs, and shortcuts:** see [Running SkyForge](/docs/use/running-skyforge.md).

***

## Provider configuration

Connecting a provider from the UI writes these blocks for you. Edit them by hand when you need options the form doesn't expose, or when you'd rather keep provider config in version control.

### API key providers

Most providers need nothing but a key.

```jsonc
{
  "provider": {
    "anthropic": { "apiKey": "sk-ant-..." },
    "openai": { "apiKey": "sk-..." },
    "google": { "apiKey": "AIza..." },
    "groq": { "apiKey": "gsk_..." },
    "openrouter": { "apiKey": "sk-or-..." }
  },
  "model": "anthropic/claude-sonnet-4-6"
}
```

Providers listed together stay available together — `model` picks the default, and **Ctrl+P → `model`** switches mid-session.

Anthropic models: `claude-opus-4-6`, `claude-sonnet-4-6`, `claude-haiku-4-5`.

### Azure OpenAI

```jsonc
{
  "provider": {
    "azure": {
      "apiKey": "your-azure-key",
      "resourceName": "your-resource-name"
    }
  },
  "model": "azure/gpt-4o"
}
```

### AWS Bedrock

```jsonc
{
  "provider": {
    "amazon-bedrock": { "region": "us-east-1" }
  }
}
```

Uses your local AWS credentials — `~/.aws/credentials` on macOS/Linux, `C:\Users\<username>\.aws\credentials` on Windows. No key goes in `skyforge.jsonc`.

### LiteLLM / vLLM

```jsonc
{
  "provider": {
    "litellm": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "LiteLLM",
      "options": {
        "baseURL": "https://your-litellm-gateway.com/v1",
        "apiKey": "sk-your-key",
        "litellmProxy": true
      },
      "models": {
        "gpt-4o": {
          "name": "GPT-4o via LiteLLM",
          "attachment": true,
          "reasoning": true,
          "modalities": {
            "input": ["text", "image"],
            "output": ["text"]
          }
        }
      }
    }
  }
}
```

> **`litellmProxy: true` is required for LiteLLM and vLLM.** It fixes tool call formatting and enables image passthrough. The Custom provider form sets it too — tick **This endpoint is a LiteLLM or vLLM proxy** — so you only need this block if you are writing the config by hand.

### Hosted gateway

```jsonc
{
  "provider": {
    "mygateway": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "My Gateway",
      "options": {
        "baseURL": "https://your-gateway.example.com/v1",
        "apiKey": "sk-..."
      },
      "models": {
        "your-model-name": { "name": "My Model" }
      }
    }
  }
}
```

### Ollama (local)

```jsonc
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "ollama": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Ollama",
      "options": { "baseURL": "http://localhost:11434/v1" },
      "models": {
        "llama3.2": { "name": "Llama 3.2" }
      }
    }
  }
}
```

***

## External MCP Servers

SkyForge supports any MCP-compatible server:

### Remote MCP (SSE/HTTP)

```jsonc
{
  "mcp": {
    "context7": {
      "type": "remote",
      "url": "https://mcp.context7.com/mcp"
    }
  }
}
```

### Local MCP (stdio)

```jsonc
{
  "mcp": {
    "my-custom-server": {
      "type": "local",
      "command": ["node", "./my-mcp-server.js"],
      "environment": {
        "API_KEY": "..."
      }
    }
  }
}
```

***

## Permissions

Control what SkyForge can do:

```jsonc
{
  "permission": {
    "bash": "ask",           // ask before running shell commands
    "write": "allow",        // allow file writes
    "read": "allow",         // allow file reads
    "external_directory": "deny"  // deny access outside project
  }
}
```

Options: `"allow"`, `"ask"`, `"deny"`

***

## Custom Agents

Define your own agents:

```jsonc
{
  "agent": {
    "servicenow-readonly": {
      "model": "anthropic/claude-haiku-4-5",
      "description": "Read-only ServiceNow queries",
      "permission": {
        "bash": "deny",
        "write": "deny"
      },
      "system": "You are a ServiceNow read-only assistant. Only query data, never create or modify anything."
    }
  }
}
```

The four built-in agents (Build, Plan, Review, General) are documented in [Running SkyForge → Agents](/docs/use/running-skyforge.md#agents).

***

## Disabling/Enabling Tools

```jsonc
{
  "tools": {
    "Bash": false,        // disable bash tool
    "WebSearch": false    // disable web search
  }
}
```

***

## Time Saved & Session Analytics

The dashboard estimates how much developer time each session saved. Classification has **two tiers**:

* **Tier 1 — rule-based (always on, free).** Maps the tools used in a session to ServiceNow deliverables (workspaces, dashboards, integrations, business rules, flows, etc.) and estimates the manual build time. Instant, no AI, zero tokens. Works in **every** setup — direct SkyForge use, local MCP, and Claude Desktop / Claude.ai over MCP. This is what you get out of the box.
* **Tier 2 — AI classification.** A smarter second pass that reasons about the work instead of pattern-matching. **Hub sessions (the SkyForge UI) always get Tier 2** — no opt-in needed — using whichever model that session itself ran on. **MCP/HTTP sessions (Claude Desktop, Claude.ai)** only get Tier 2 when you opt in, since they have no session model of their own to fall back to the way Hub sessions do.

> You don't need to do anything for either tier by default — Hub sessions already get real Tier 2 for free, and MCP sessions get solid Tier 1. `analytics.aiClassification` is for **pinning a specific model**, not for "turning AI on" — it's already on for the Hub.

### From the Hub UI

[**Hub → Analytics**](/docs/use/analytics.md) tab has the full setting — a toggle, a model dropdown sourced from your already-connected providers (model selection is required once the toggle is on; there's no silent "default model" fallback in the UI), and the MCP settle window below it. This writes the same `analytics` keys described below.

### Enabling classifier model pinning (Tier 2 override)

Three keys under `analytics` in `skyforge.jsonc`:

```jsonc
{
  "analytics": {
    "aiClassification": true,                          // pin a specific model for BOTH Hub and MCP (default: false)
    "classifierModel": "openai/gpt-4o-mini",            // which provider/model to pin
    "mcpSettleMinutes": 30                              // MCP-only: idle minutes before a session is eligible (default: 30)
    // examples: "openai/gpt-4o-mini", "anthropic/claude-haiku-4-5",
    //           "google/gemini-2.5-flash", "groq/llama-3.3-70b"
  }
}
```

| Key                          | Default               | Purpose                                                                                                                                                                                                                                                                |
| ---------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `analytics.aiClassification` | `false`               | **Hub:** whether to override the session's own model with `classifierModel` (Tier 2 itself always runs regardless). **MCP:** master on/off for Tier 2 — off stays Tier 1 only.                                                                                         |
| `analytics.classifierModel`  | account default model | `"providerID/modelID"` — which configured provider/model to pin, when `aiClassification` is `true`.                                                                                                                                                                    |
| `analytics.mcpSettleMinutes` | `30`                  | MCP-only. How long an MCP session must sit idle before it's eligible for AI classification — prevents classifying mid-work. Takes precedence over the `SN_MCP_SESSION_IDLE_MS` env var when set. No effect on Hub sessions, which classify immediately on session end. |

Turn pinning on with no model chosen — MCP sessions get Tier 2 via the account's default model; Hub sessions switch from their own session model to that same default too:

```jsonc
{ "analytics": { "aiClassification": true } }
```

Leave it off (or omit `analytics` entirely) — MCP stays Tier 1 only; Hub keeps using each session's own model, unaffected either way. This is the default and the out-of-the-box Hub behavior.

### Running Tier 2 on demand for one session

`POST /api/analytics/sessions/:id/analyze?ai=true` forces AI classification for that one session right away — bypassing the 30-minute (or configured) settle window and the dedup guard. Still requires `analytics.aiClassification: true` and a configured provider; otherwise it silently stays rule-based. The Hub does this for you: on the Sessions & Tasks list (Overview and Activity tabs), any session still showing the **RULES** badge has a **Run AI** button next to it.

### Where the API key goes

`classifierModel` is **only a pointer** to a provider you've already set up under `provider` (see [AI Providers](/docs/connect/ai-providers.md)) — there is **no API-key field here**. The key for that provider is read from your normal provider config / `auth.json` / environment variable. So the `providerID` in `classifierModel` must match a provider you've configured. If it has no key, Tier 2 silently falls back to Tier 1.

> **Keys → provider config / `auth.json`. Which model to use → `analytics.classifierModel`. The analytics block never holds a secret.**

### Notes

* **Non-breaking.** The `analytics` block is optional and defaults off. Existing installs need no changes — Hub sessions already got Tier 2 before this block existed; MCP sessions keep getting Tier 1.
* **Hub sessions use their own model by default, not SkyForge's "default" model.** Only when `aiClassification` is `true` does a Hub session switch to `classifierModel` (or the account default) instead of the model that session was actually run with.
* **MCP needs the SkyForge install itself to have a provider configured.** When Claude Desktop drives SkyForge over MCP, Claude executes tools but never provides the classifier's model — Tier 2 for MCP sessions needs **the SkyForge install** (the one running the dashboard) to have a provider configured, and `aiClassification` turned on. If you only use SkyForge as an MCP relay and never configured a provider, MCP sessions stay on Tier 1 regardless of this setting.
* **Same key/budget as your dev work.** Classification calls bill to the same provider account. Point `classifierModel` at a cheap model to keep it inexpensive.

***

## Environment Variables

Instead of `skyforge.jsonc`, you can use environment variables:

```bash
export ANTHROPIC_API_KEY="sk-ant-..."
export OPENAI_API_KEY="sk-..."
export SERVICENOW_INSTANCE_URL="https://dev12345.service-now.com"
export SERVICENOW_CLIENT_ID="abc123"
export SERVICENOW_CLIENT_SECRET="secret"

skyforge
```

### ServiceNow

Most of these are read under either prefix — `server.ts:186-190` accepts `SERVICENOW_*` first and falls back to `SN_*`.

| Variable                   | Alias              | Purpose                                                   |
| -------------------------- | ------------------ | --------------------------------------------------------- |
| `SERVICENOW_INSTANCE_URL`  | `SN_INSTANCE`      | Instance URL. The alias accepts a bare name or a full URL |
| `SERVICENOW_USERNAME`      | `SN_USERNAME`      | Basic auth username                                       |
| `SERVICENOW_PASSWORD`      | `SN_PASSWORD`      | Basic auth password                                       |
| `SERVICENOW_CLIENT_ID`     | `SN_CLIENT_ID`     | OAuth client ID                                           |
| `SERVICENOW_CLIENT_SECRET` | `SN_CLIENT_SECRET` | OAuth client secret                                       |
| `SERVICENOW_REFRESH_TOKEN` | `SN_REFRESH_TOKEN` | OAuth refresh token, to skip the browser flow             |

### Ports and networking

Covered in full in [Running SkyForge → Ports & Server](/docs/use/running-skyforge.md#ports--server).

| Variable               | Default     | Purpose                                                                                                 |
| ---------------------- | ----------- | ------------------------------------------------------------------------------------------------------- |
| `OPENCODE_SERVER_PORT` | `4096`      | Web UI and API port                                                                                     |
| `SN_MCP_HTTP_PORT`     | `3006`      | HTTP MCP server port                                                                                    |
| `SN_MCP_HTTP_HOST`     | `127.0.0.1` | HTTP MCP bind address. Opening this up exposes stored credentials — read the warning on that page first |
| `SN_OAUTH_PORT`        | `3005`      | Local port the OAuth callback lands on. Must match the Redirect URL registered in ServiceNow            |

### Diagnostics and behaviour

| Variable                 | Purpose                                                                                                                                                                                                                                          |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `SN_MCP_DEBUG`           | `true` turns on verbose MCP logging                                                                                                                                                                                                              |
| `SN_LAZY_TOOLS`          | Controls deferred tool loading. Tools are lazy by default                                                                                                                                                                                        |
| `SN_MCP_SESSION_IDLE_MS` | How long an MCP session may idle before it counts as ended, for analytics. Overridden by `analytics.mcpSettleMinutes` in `skyforge.jsonc` (or the Hub UI) when that's set — see [Time Saved & Session Analytics](#time-saved--session-analytics) |
| `SN_MEMORY_PATH`         | Override the location `sn_memory_search` reads from                                                                                                                                                                                              |

***

## Full Config Reference

```jsonc
{
  // AI provider configurations
  "provider": {
    "anthropic": { "apiKey": "..." },
    "openai": { "apiKey": "..." }
  },

  // Default model (provider/model format)
  "model": "anthropic/claude-sonnet-4-6",

  // Small model for lightweight tasks (title generation etc.)
  "model.mini": "anthropic/claude-haiku-4-5",

  // MCP server configurations
  "mcp": {
    "servicenow": { ... }
  },

  // Tool enable/disable
  "tools": {
    "Bash": true,
    "WebSearch": true
  },

  // Permissions
  "permission": {
    "bash": "ask",
    "write": "allow",
    "read": "allow"
  },

  // Disable specific providers
  "disabled_providers": ["openrouter"],

  // Only enable specific providers
  "enabled_providers": ["anthropic", "openai"],

  // Session analytics / Time Saved (Tier 2 AI classification — Hub always on, MCP opt-in)
  "analytics": {
    "aiClassification": false,                      // pin classifierModel for BOTH Hub + MCP (default off — Hub still gets Tier 2 via its own session model either way)
    "classifierModel": "openai/gpt-4o-mini",         // optional — "provider/model" of a configured provider
    "mcpSettleMinutes": 30                           // optional — MCP-only idle window before eligible (default: 30)
    // e.g. "anthropic/claude-haiku-4-5", "google/gemini-2.5-flash"
  },

  // Custom agents
  "agent": { ... },

  // Plugins (npm packages)
  "plugin": ["my-skyforge-plugin"]
}
```

***

## Troubleshooting

See the [Troubleshooting](/docs/reference/troubleshooting.md) page.

***

## Support

Have a bug or feature request? Submit it at [**GitHub Issues**](https://github.com/tryskyforge/skyforgeissues).
