---
title: heretic-cli init
description: "The interactive setup wizard — GitHub and Copilot tokens, secret script generation, Anthropic API-key vs OAuth modes, third-party presets (ZAI, Kimi, custom), Copilot agents, and every file it writes"
canonical: https://giglabo.com/heretic/docs/heretic-cli/commands/init
locale: en
---

# heretic-cli init

> Markdown twin of https://giglabo.com/heretic/docs/heretic-cli/commands/init
> Fetch this instead of the HTML page: same content, a fraction of the bytes.
> Site structure and the full page list for agents: https://giglabo.com/llms.txt

The interactive setup wizard — GitHub and Copilot tokens, secret script generation, Anthropic API-key vs OAuth modes, third-party presets (ZAI, Kimi, custom), Copilot agents, and every file it writes

## Synopsis

```bash
heretic-cli init          # no options other than -h/--help
```

Two phases: **GitHub tokens** → `~/.heretic/settings.yaml`, then an **agent profile loop** → `~/.heretic/agents/`. The wizard is idempotent — re-run it to change tokens or add agents.

> **Warning: Interactive only**
>
> `init` has no flags and cannot run in CI. To provision a machine non-interactively, write `~/.heretic/settings.yaml` and `~/.heretic/agents/<name>.yaml` yourself, then verify with `heretic-cli agents validate`.

## Phase 1 — GitHub tokens

```
Enter your GitHub token (optional, press Enter to skip):
Enter GitHub Copilot token (optional, press Enter to skip):
```

Existing values are shown **masked** (first 8 characters + `****` + last 4; anything shorter than 12 characters becomes `****`). Submitting the masked default unchanged keeps the existing script path — the comparison is literal, so do not hand-edit the masked value.

For each new token a secret script is written, and only its **path** is stored:

| Platform | File | Contents |
|----------|------|----------|
| Unix | `~/.heretic/get-github-token-key.sh` (mode `0755`) | `#!/bin/bash` + `echo "<token>"` + commented examples for 1Password / Keychain / pass |
| Windows | `~/.heretic/get-github-token-key.cmd` | `@echo off` plus an `echo`/`set /p` pair that prints the token without a trailing newline |

The Copilot token uses `get-copilot-token-key.sh` / `.cmd`.

```yaml
# ~/.heretic/settings.yaml
github:
  token: /home/you/.heretic/get-github-token-key.sh
  copilot_token: /home/you/.heretic/get-copilot-token-key.sh
```

Both fields also accept a **raw token** for backward compatibility: the value is only executed when it ends in `.sh`, `.cmd`, `.ps1` or `.bat`.

These tokens are injected into every container as `GH_TOKEN` and `GITHUB_TOKEN`, and additionally as `GH_COPILOT_TOKEN` / `GITHUB_COPILOT_TOKEN` when the profile has `provider: copilot` (falling back to the GitHub token if no Copilot token is set).

### Token security

The generated script is a deliberate seam — replace its body with your own secret store:

```bash
# Unix (.sh)
security find-generic-password -s 'github-token' -w      # macOS Keychain
op read 'op://vault/github/token'                        # 1Password CLI
pass show github/token                                   # pass
gh auth token                                            # GitHub CLI
```

```cmd
@echo off
op read "op://vault/github/token"
```

```powershell
(Get-StoredCredential -Target "github-token").GetNetworkCredential().Password
```

The shell is chosen by extension: `.sh` → `bash` (Git Bash or WSL on Windows), `.cmd` / `.bat` → `cmd.exe`, `.ps1` → `powershell -ExecutionPolicy Bypass -File`. On Windows the wizard only generates `.cmd`; `.ps1` scripts work but must be created by hand.

## Phase 2 — agent profiles

```
=== Current Agent Profiles ===
1. claude - giglabo/claude-heretic (docker)

What would you like to do?
  > Add new agent
    Delete agent          (only when at least one profile exists)
    Done managing agents
```

`Add new agent` starts with the agent type:

| Choice | `provider` | `agent_type` | Token |
|--------|-----------|--------------|-------|
| Anthropic (direct API) | `anthropic` | `claude` | optional |
| Third-Party (ZAI, Kimi, or custom) | `thirdparty` | `claude` | required |
| Copilot (custom API) | `copilot` | `copilot-cli` | optional |

Profile names must match `[a-z0-9-_]+` (case-insensitive). If `~/.heretic/agents/<name>.yaml` exists you are asked to confirm the overwrite.

### Anthropic flow

Prompts: name (default `claude`) → Docker image (default `giglabo/claude-heretic`) → token (optional) → **token type** (only when a token was given) → optional path to an existing `settings.json`.

| Token type | Environment written into the profile | Use case |
|------------|--------------------------------------|----------|
| **API Key** | `ANTHROPIC_API_KEY` — the docker runner maps it to `ANTHROPIC_AUTH_TOKEN` **and** `ANTHROPIC_AUTH_KEY` | pay-per-use API billing |
| **OAuth Token** | `CLAUDE_CODE_OAUTH_TOKEN`, plus `ANTHROPIC_AUTH_TOKEN: ""` and `ANTHROPIC_BASE_URL: ""` | Claude subscription |

The empty strings are intentional: they stop Claude Code from falling back to API mode. Empty values are normally stripped from the container environment, but a key explicitly set to `""` in `env` is preserved.

### Third-party flow (ZAI / Kimi / custom)

| Preset | Base URL | Model | Small / fast model | Default name |
|--------|----------|-------|--------------------|--------------|
| `zai` | `https://api.z.ai/api/anthropic` | `glm-4.7` | `glm-4.5-air` | `claude-zai` |
| `kimi` | `https://api.moonshot.ai/anthropic` | `kimi-k2.5` | `kimi-k2.5` | `claude-kimi` |
| `custom` | you enter it (validated as a URL) | you enter it | you enter it | `claude-thirdparty` |

All presets seed `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1` and `API_TIMEOUT_MS=600000`. You then choose **Keep defaults**, **Modify default values**, or **Add more env vars** (a loop that ends on an empty name; names must match `[A-Z_][A-Z0-9_]*`).

Next you decide **where the model configuration lives**:

- *Environment Variables* — the six model variables go into the profile's `env`
- *Settings JSON* — they go into the `env` block of `~/.heretic/<name>-settings.json` instead (or you point at an existing settings file, which must exist)

The six variables:

```
main   ANTHROPIC_MODEL, ANTHROPIC_DEFAULT_OPUS_MODEL, ANTHROPIC_DEFAULT_SONNET_MODEL
small  ANTHROPIC_SMALL_FAST_MODEL, ANTHROPIC_DEFAULT_HAIKU_MODEL, CLAUDE_CODE_SUBAGENT_MODEL
```

Leaving the small model blank makes it fall back to the primary model.

### Copilot flow

Prompts: name (default `copilot`) → Docker image (**required**, no default) → optional dedicated token. With a dedicated token the profile gets a `PROFILENAME_TOKEN` variable fed from the matching `PROFILENAME_API_KEY` secret — the profile name uppercased with dashes turned into underscores, so `my-copilot` becomes `MY_COPILOT_TOKEN`; without one the container relies on the global `GH_COPILOT_TOKEN` / `GITHUB_COPILOT_TOKEN` injection. No `ANTHROPIC_*` variables and no Claude settings file are created for Copilot agents.

## What a created profile looks like

```yaml
image: giglabo/claude-heretic
runner: docker
agent_type: claude              # copilot-cli when provider is copilot
provider: anthropic             # anthropic | thirdparty | copilot
description: Anthropic agent    # or "Third-party agent (zai)" / "Copilot agent"
interactive: true
tty: true
volumes:
  - source: ${CWD}
    target: /workspace
workdir: /workspace
env: {}                         # provider-specific, see above
claude_settings: /home/you/.heretic/claude-settings.json   # omitted for copilot
secrets:
  CLAUDE_API_KEY: /home/you/.heretic/get-claude-key.sh     # only when a token was given
```

The secret variable name is derived from the profile name: uppercase, `-` → `_`, suffix `_API_KEY` (so `claude-zai` → `CLAUDE_ZAI_API_KEY`). A secret that is not also referenced in `env` is resolved but **not** exported into the container — it exists only for `${…}` interpolation.

## Default Claude settings file

When you do not supply an existing settings file, `~/.heretic/<name>-settings.json` is created as:

```json
{
  "permissions": {
    "allow": ["Read", "Edit", "Write", "Bash", "WebFetch", "WebSearch", "mcp__*"]
  },
  "model": "opus"
}
```

At run time this is merged with the project's `.heretic/cli/claude-settings.json` (arrays unioned, objects shallow-merged, local wins) and mounted as `~/.claude/settings.json` inside the container.

## Deleting from the wizard vs `agents delete`

The wizard's **Delete agent** removes only three paths and never touches containers: `~/.heretic/agents/<name>.yaml`, `~/.heretic/get-<name>-key.sh`, `~/.heretic/<name>-settings.json`. It does not remove Windows `.cmd` scripts. Use [`heretic-cli agents delete <name>`](https://giglabo.com/heretic/docs/heretic-cli/commands/agents) for a complete removal including containers.

## Final summary

```
=== Configuration Complete ===
GitHub Token: ghp_xxxx****abcd
GitHub Copilot Token: (not configured)

Agent Profiles: 2
  - claude
  - claude-zai

Run an agent with: heretic-cli <profile-name>
```

## Gotchas

- Tokens are stored **in plaintext inside the generated script** — protect the file, or replace its body with a secret-manager call.
- `init` never creates project-local configuration; that is [`local-init`](https://giglabo.com/heretic/docs/heretic-cli/commands/local-init).
- The directories `~/.heretic` and `~/.heretic/agents` are created up front, so a cancelled wizard can leave an empty profile directory behind.
- A secret script that prints nothing logs `Secret script returned empty value` (a warning, not an error) and the variable ends up empty — and then gets stripped from the container environment.

## Next Steps

- [agents](https://giglabo.com/heretic/docs/heretic-cli/commands/agents) — inspect, edit and validate what the wizard created
- [Secrets](https://giglabo.com/heretic/docs/heretic-cli/configuration/secrets) — the three secret value modes
- [Agent Profiles](https://giglabo.com/heretic/docs/heretic-cli/configuration/agent-profiles) — the full profile schema

## Related

- HTML version of this page: https://giglabo.com/heretic/docs/heretic-cli/commands/init
- Site map for agents: https://giglabo.com/llms.txt
