subconscious-cli 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "_generated": "Source of truth: agents/registry.json. Do not edit by hand.",
3
3
  "defaults": {
4
- "model": "subconscious/tim-qwen3.6-27b",
4
+ "model": "subconscious/glm-5.2",
5
+ "models": [
6
+ "subconscious/glm-5.2",
7
+ "subconscious/tim-qwen3.6-27b",
8
+ "subconscious/deepseek-v4-flash-marathon"
9
+ ],
5
10
  "baseUrl": "https://api.subconscious.dev",
6
11
  "baseUrlV1": "https://api.subconscious.dev/v1",
7
12
  "keyPlaceholder": "your_key",
@@ -10,14 +15,15 @@
10
15
  "agents": [
11
16
  {
12
17
  "id": "claude-code",
18
+ "command": "claude",
13
19
  "exampleDir": "claude_code",
14
20
  "name": "Claude Code",
15
21
  "aliases": [
16
- "claude",
22
+ "claude-code",
17
23
  "claudecode"
18
24
  ],
19
25
  "displayName": "Claude Code + Subconscious",
20
- "description": "Run Claude Code on your hosted Subconscious model no code changes, just env vars.",
26
+ "description": "Run Claude Code on your hosted Subconscious model with gateway env, context limits, and telemetry.",
21
27
  "framework": "Claude Code",
22
28
  "language": "shell",
23
29
  "category": "coding-agent",
@@ -35,24 +41,95 @@
35
41
  "win32": "powershell -ExecutionPolicy Bypass -Command \"irm https://claude.ai/install.ps1 | iex\"",
36
42
  "fallback": "npm i -g @anthropic-ai/claude-code"
37
43
  },
44
+ "runbook": {
45
+ "mode": "launch",
46
+ "script": "claude-code/run.sh",
47
+ "setupScript": "claude-code/install.sh",
48
+ "setupActions": [
49
+ "status",
50
+ "uninstall"
51
+ ]
52
+ },
38
53
  "launch": "claude",
39
54
  "env": {
40
55
  "ANTHROPIC_BASE_URL": "{baseUrl}",
41
56
  "ANTHROPIC_AUTH_TOKEN": "{apiKey}",
42
57
  "ANTHROPIC_MODEL": "{model}",
43
58
  "ANTHROPIC_SMALL_FAST_MODEL": "{model}",
44
- "DISABLE_AUTO_COMPACT": "true"
59
+ "ANTHROPIC_DEFAULT_OPUS_MODEL": "subconscious/glm-5.2",
60
+ "ANTHROPIC_DEFAULT_OPUS_MODEL_NAME": "subconscious/glm-5.2",
61
+ "ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION": "Subconscious default model",
62
+ "ANTHROPIC_DEFAULT_SONNET_MODEL": "subconscious/tim-qwen3.6-27b",
63
+ "ANTHROPIC_DEFAULT_SONNET_MODEL_NAME": "subconscious/tim-qwen3.6-27b",
64
+ "ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION": "Subconscious TIM Qwen 3.6 27B",
65
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL": "subconscious/deepseek-v4-flash-marathon",
66
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME": "subconscious/deepseek-v4-flash-marathon",
67
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION": "Subconscious DeepSeek V4 Flash Marathon",
68
+ "CLAUDE_CODE_SUBAGENT_MODEL": "{model}",
69
+ "CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS": "4",
70
+ "CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH": "1",
71
+ "CLAUDE_CODE_AUTO_COMPACT_WINDOW": "1000000",
72
+ "CLAUDE_CODE_MAX_CONTEXT_TOKENS": "3000000",
73
+ "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
74
+ "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
75
+ "OTEL_LOGS_EXPORTER": "otlp",
76
+ "OTEL_EXPORTER_OTLP_PROTOCOL": "http/json",
77
+ "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT": "{baseUrl}/v1/logs",
78
+ "OTEL_EXPORTER_OTLP_HEADERS": "x-api-key={apiKey}",
79
+ "OTEL_EXPORTER_OTLP_TIMEOUT": "2000",
80
+ "OTEL_LOGS_EXPORT_INTERVAL": "2000"
81
+ }
82
+ },
83
+ {
84
+ "id": "codex",
85
+ "command": "codex",
86
+ "exampleDir": "codex",
87
+ "name": "Codex CLI",
88
+ "aliases": [],
89
+ "displayName": "Codex + Subconscious",
90
+ "description": "Run Codex on your hosted Subconscious model with a temporary provider catalog and compaction hooks.",
91
+ "framework": "Codex",
92
+ "language": "shell",
93
+ "category": "coding-agent",
94
+ "tags": [
95
+ "local",
96
+ "cli",
97
+ "agents"
98
+ ],
99
+ "protocol": "openai",
100
+ "homepage": "https://developers.openai.com/codex",
101
+ "bin": "codex",
102
+ "install": {
103
+ "darwin": "npm i -g @openai/codex",
104
+ "linux": "npm i -g @openai/codex",
105
+ "win32": "npm i -g @openai/codex"
106
+ },
107
+ "runbook": {
108
+ "mode": "launch",
109
+ "script": "codex/run.sh",
110
+ "setupScript": "codex/install.sh",
111
+ "setupActions": [
112
+ "install",
113
+ "status",
114
+ "uninstall"
115
+ ]
116
+ },
117
+ "launch": "codex -c model={model} -c model_provider=subconscious -c web_search=disabled -c model_providers.subconscious.name=Subconscious -c model_providers.subconscious.base_url={baseUrlV1} -c model_providers.subconscious.wire_api=responses -c model_providers.subconscious.env_key=SUBCONSCIOUS_API_KEY -c model_providers.subconscious.stream_idle_timeout_ms=300000",
118
+ "env": {
119
+ "SUBCONSCIOUS_API_KEY": "{apiKey}",
120
+ "SUBCONSCIOUS_GATEWAY_URL": "{baseUrl}"
45
121
  }
46
122
  },
47
123
  {
48
124
  "id": "opencode",
125
+ "command": "opencode",
49
126
  "exampleDir": "opencode",
50
127
  "name": "OpenCode",
51
128
  "aliases": [
52
129
  "open-code"
53
130
  ],
54
131
  "displayName": "OpenCode + Subconscious",
55
- "description": "Run OpenCode on your hosted Subconscious model registered as a custom provider, injected non-invasively (nothing written to your OpenCode config).",
132
+ "description": "Run OpenCode on your hosted Subconscious model with the Subconscious provider and context settings.",
56
133
  "framework": "OpenCode",
57
134
  "language": "shell",
58
135
  "category": "coding-agent",
@@ -69,25 +146,58 @@
69
146
  "linux": "npm i -g opencode-ai",
70
147
  "win32": "npm i -g opencode-ai"
71
148
  },
149
+ "runbook": {
150
+ "mode": "launch",
151
+ "script": "opencode/run.sh",
152
+ "setupScript": "opencode/install.sh",
153
+ "setupActions": [
154
+ "status",
155
+ "uninstall"
156
+ ]
157
+ },
72
158
  "launch": "opencode",
73
159
  "configEnv": "OPENCODE_CONFIG_CONTENT",
74
160
  "env": {
75
161
  "SUBCONSCIOUS_API_KEY": "{apiKey}",
162
+ "SUBCONSCIOUS_GATEWAY_URL": "{baseUrl}",
76
163
  "OPENCODE_CONFIG_CONTENT": {
77
164
  "$json": {
78
165
  "$schema": "https://opencode.ai/config.json",
79
166
  "provider": {
80
167
  "subconscious": {
81
168
  "npm": "@ai-sdk/openai-compatible",
82
- "name": "Subconscious",
169
+ "name": "Subconscious Gateway",
83
170
  "options": {
84
171
  "baseURL": "{baseUrlV1}",
85
- "apiKey": "{env:SUBCONSCIOUS_API_KEY}"
172
+ "apiKey": "{env:SUBCONSCIOUS_API_KEY}",
173
+ "headers": {
174
+ "x-subconscious-client": "opencode"
175
+ }
86
176
  },
87
177
  "models": {
88
- "{model}": {
89
- "name": "Subconscious",
90
- "tools": true
178
+ "subconscious/glm-5.2": {
179
+ "name": "subconscious/glm-5.2",
180
+ "tools": true,
181
+ "limit": {
182
+ "context": 5000000,
183
+ "output": 65536
184
+ }
185
+ },
186
+ "subconscious/tim-qwen3.6-27b": {
187
+ "name": "subconscious/tim-qwen3.6-27b",
188
+ "tools": true,
189
+ "limit": {
190
+ "context": 5000000,
191
+ "output": 65536
192
+ }
193
+ },
194
+ "subconscious/deepseek-v4-flash-marathon": {
195
+ "name": "subconscious/deepseek-v4-flash-marathon",
196
+ "tools": true,
197
+ "limit": {
198
+ "context": 5000000,
199
+ "output": 65536
200
+ }
91
201
  }
92
202
  }
93
203
  }
@@ -98,42 +208,69 @@
98
208
  }
99
209
  },
100
210
  {
101
- "id": "aider",
102
- "exampleDir": "aider",
103
- "name": "Aider",
211
+ "id": "cursor",
212
+ "command": "cursor",
213
+ "name": "Cursor",
104
214
  "aliases": [],
105
- "displayName": "Aider + Subconscious",
106
- "description": "Run Aider on your hosted Subconscious model — no code changes, just env vars.",
107
- "framework": "Aider",
215
+ "description": "Install Cursor conversation and compaction hooks, then finish model setup in Cursor Settings.",
216
+ "framework": "Cursor",
108
217
  "language": "shell",
109
218
  "category": "coding-agent",
110
219
  "tags": [
111
220
  "local",
112
- "cli",
221
+ "ide",
113
222
  "agents"
114
223
  ],
115
224
  "protocol": "openai",
116
- "homepage": "https://aider.chat",
117
- "bin": "aider",
118
- "install": {
119
- "darwin": "python3 -m pip install aider-install && aider-install",
120
- "linux": "python3 -m pip install aider-install && aider-install",
121
- "win32": "python -m pip install aider-install && aider-install"
122
- },
123
- "launch": "aider --model openai/{model}",
124
- "env": {
125
- "OPENAI_API_BASE": "{baseUrlV1}",
126
- "OPENAI_API_KEY": "{apiKey}"
225
+ "homepage": "https://cursor.com",
226
+ "runbook": {
227
+ "mode": "setup",
228
+ "script": "cursor/install.sh",
229
+ "setupScript": "cursor/install.sh",
230
+ "setupActions": [
231
+ "install",
232
+ "status",
233
+ "uninstall"
234
+ ]
127
235
  }
128
236
  },
129
237
  {
130
- "id": "codex",
131
- "exampleDir": "codex",
132
- "name": "Codex CLI",
238
+ "id": "copilot",
239
+ "command": "copilot",
240
+ "name": "GitHub Copilot (VS Code)",
241
+ "aliases": [
242
+ "vscode",
243
+ "vs-code"
244
+ ],
245
+ "description": "Install the VS Code custom endpoint and Copilot conversation/compaction hooks.",
246
+ "framework": "GitHub Copilot",
247
+ "language": "shell",
248
+ "category": "coding-agent",
249
+ "tags": [
250
+ "local",
251
+ "ide",
252
+ "agents"
253
+ ],
254
+ "protocol": "openai",
255
+ "homepage": "https://code.visualstudio.com/docs/copilot/overview",
256
+ "runbook": {
257
+ "mode": "setup",
258
+ "script": "copilot/install.sh",
259
+ "setupScript": "copilot/install.sh",
260
+ "setupActions": [
261
+ "install",
262
+ "status",
263
+ "uninstall"
264
+ ]
265
+ }
266
+ },
267
+ {
268
+ "id": "pi",
269
+ "command": "pi",
270
+ "name": "Pi",
133
271
  "aliases": [],
134
- "displayName": "Codex + Subconscious",
135
- "description": "Run the Codex CLI on your hosted Subconscious model via a custom OpenAI-compatible provider.",
136
- "framework": "Codex",
272
+ "description": "Launch Pi with the Subconscious provider and active profile model configured by subc pi install.",
273
+ "framework": "Pi",
137
274
  "language": "shell",
138
275
  "category": "coding-agent",
139
276
  "tags": [
@@ -142,16 +279,17 @@
142
279
  "agents"
143
280
  ],
144
281
  "protocol": "openai",
145
- "homepage": "https://developers.openai.com/codex",
146
- "bin": "codex",
147
- "install": {
148
- "darwin": "npm i -g @openai/codex",
149
- "linux": "npm i -g @openai/codex",
150
- "win32": "npm i -g @openai/codex"
151
- },
152
- "launch": "codex -c model_providers.subconscious.name=Subconscious -c model_providers.subconscious.base_url={baseUrlV1} -c model_providers.subconscious.env_key=SUBCONSCIOUS_API_KEY -c model_provider=subconscious -c model={model}",
153
- "env": {
154
- "SUBCONSCIOUS_API_KEY": "{apiKey}"
282
+ "homepage": "https://pi.dev",
283
+ "bin": "pi",
284
+ "runbook": {
285
+ "mode": "launch",
286
+ "script": "pi/run.sh",
287
+ "setupScript": "pi/install.sh",
288
+ "setupActions": [
289
+ "install",
290
+ "status",
291
+ "uninstall"
292
+ ]
155
293
  }
156
294
  }
157
295
  ]
@@ -0,0 +1,22 @@
1
+ # Coding-agent integrations
2
+
3
+ These scripts are part of `subc`. They launch or surgically install Claude Code,
4
+ Codex, OpenCode, Cursor, Copilot, and Pi against the Subconscious gateway.
5
+
6
+ `subc` reads `~/.subconscious/profiles/<name>.env` and injects those values into
7
+ the scripts, so users do not need a sibling `.env` file. When a script is run
8
+ directly, `SUBC_ENV_FILE` (or `cli/bin/runbook/.env`) can supply the same keys.
9
+
10
+ Included integrations:
11
+
12
+ - `claude-code/install.sh` and `run.sh`
13
+ - `codex/install.sh`, `run.sh`, `hook.sh`, `hooks.json`, and `hooks-lib.sh`
14
+ - `opencode/install.sh`, `run.sh`, and `subconscious-compaction.ts`
15
+ - `cursor/install.sh`, `hook.sh`, and `hooks.json`
16
+ - `copilot/install.sh`, `hook.sh`, and `hooks.json`
17
+ - `pi/install.sh`, `run.sh`, and `subconscious-compaction.ts`
18
+
19
+ Each CLI-enabled entry in `agents/registry.json` points here with a `runbook`
20
+ block. Persistent writes are merge/unmerge only: they never replace a user's
21
+ `config.toml`, `opencode.json`, `models.json`, `hooks.json`, or VS Code
22
+ provider list.
@@ -0,0 +1,290 @@
1
+ #!/usr/bin/env bash
2
+ # ── Subconscious API Gateway — Claude Code setup ──────────────────────────────
3
+ # Point Claude Code at your gateway. Claude reads env vars, so the "install"
4
+ # writes them to ~/.claude/subconscious-gateway.env and `use` launches claude.
5
+ #
6
+ # Quick start:
7
+ # ./install.sh --gateway-url https://your-gateway.example --api-key sk-gw-...
8
+ # ./install.sh use # launches claude with gateway env loaded
9
+ # ./install.sh use -- --continue # pass args through to claude
10
+ #
11
+ # Or source env into your shell:
12
+ # source <(./install.sh env) # load ANTHROPIC_BASE_URL etc.
13
+ # source <(./install.sh unset) # remove ANTHROPIC_BASE_URL etc.
14
+ #
15
+ # ./install.sh status # show current config
16
+ # ./install.sh uninstall # remove env file
17
+ #
18
+ # ── What this does under the hood ────────────────────────────────────────────
19
+ # Equivalent manual setup (no script needed):
20
+ #
21
+ # export ANTHROPIC_BASE_URL=https://your-gateway.example
22
+ # export ANTHROPIC_AUTH_TOKEN=sk-gw-...
23
+ # export ANTHROPIC_MODEL=subconscious/glm-5.2
24
+ # export ANTHROPIC_SMALL_FAST_MODEL=subconscious/glm-5.2
25
+ # export CLAUDE_CODE_SUBAGENT_MODEL=subconscious/glm-5.2
26
+ # export CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS=4
27
+ # export CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1
28
+ # export CLAUDE_CODE_AUTO_COMPACT_WINDOW=1000000
29
+ # export CLAUDE_CODE_MAX_CONTEXT_TOKENS=3000000
30
+ # # AUTO_COMPACT_WINDOW range 100000–1000000 (leave on; TIMRUN keys rarely hit it):
31
+ # # https://code.claude.com/docs/en/env-vars
32
+ # # https://code.claude.com/docs/en/context-window#set-the-auto-compact-window
33
+ # export CLAUDE_CODE_ENABLE_TELEMETRY=1
34
+ # export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
35
+ # export OTEL_LOGS_EXPORTER=otlp
36
+ # export OTEL_EXPORTER_OTLP_PROTOCOL=http/json
37
+ # export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://your-gateway.example/v1/logs
38
+ # export OTEL_EXPORTER_OTLP_HEADERS="x-api-key=sk-gw-..."
39
+ # export OTEL_EXPORTER_OTLP_TIMEOUT=2000
40
+ # export OTEL_LOGS_EXPORT_INTERVAL=2000
41
+ # claude
42
+ #
43
+ # Claude Code sends native x-claude-code-session-id headers, so the gateway
44
+ # correlates requests automatically. OTEL api_request logs → Claude Code-only
45
+ # POST /v1/logs back-fill query_source (not a general logs API):
46
+ # https://code.claude.com/docs/en/monitoring-usage#api-request-event
47
+ # ─────────────────────────────────────────────────────────────────────────────
48
+
49
+ set -euo pipefail
50
+
51
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
52
+
53
+ # Load shared env from SUBC_ENV_FILE, or a sibling .env / env.example.
54
+ SHARED_ENV="${SUBC_ENV_FILE:-${SCRIPT_DIR}/../.env}"
55
+ [[ -f "$SHARED_ENV" ]] || SHARED_ENV="${SCRIPT_DIR}/../env.example"
56
+ if [[ -f "$SHARED_ENV" ]]; then set -a; source "$SHARED_ENV"; set +a; fi
57
+
58
+ CLAUDE_DIR="${HOME}/.claude"
59
+ ENV_FILE="${CLAUDE_DIR}/subconscious-gateway.env"
60
+ DEFAULT_MODEL="subconscious/glm-5.2"
61
+ DEFAULT_COMPACT_WINDOW="1000000"
62
+ DEFAULT_MAX_CONTEXT_TOKENS="3000000"
63
+ DEFAULT_MAX_CONCURRENT_SUBAGENTS="4"
64
+ DEFAULT_MAX_SUBAGENT_SPAWN_DEPTH="1"
65
+ DEFAULT_OPUS_MODEL="subconscious/glm-5.2"
66
+ DEFAULT_SONNET_MODEL="subconscious/tim-qwen3.6-27b"
67
+ DEFAULT_HAIKU_MODEL="subconscious/deepseek-v4-flash-marathon"
68
+
69
+ GATEWAY_URL="${GATEWAY_URL:-}"
70
+ API_KEY="${CLAUDE_CODE_API_KEY:-${API_KEY:-}}"
71
+ MODEL="${MODEL:-$DEFAULT_MODEL}"
72
+ COMPACT_WINDOW="${CLAUDE_CODE_AUTO_COMPACT_WINDOW:-${COMPACT_WINDOW:-$DEFAULT_COMPACT_WINDOW}}"
73
+ MAX_CONTEXT_TOKENS="${CLAUDE_CODE_MAX_CONTEXT_TOKENS:-${MAX_CONTEXT_TOKENS:-$DEFAULT_MAX_CONTEXT_TOKENS}}"
74
+ MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS:-$DEFAULT_MAX_CONCURRENT_SUBAGENTS}"
75
+ MAX_SUBAGENT_SPAWN_DEPTH="${MAX_SUBAGENT_SPAWN_DEPTH:-$DEFAULT_MAX_SUBAGENT_SPAWN_DEPTH}"
76
+ OPUS_MODEL="${ANTHROPIC_DEFAULT_OPUS_MODEL:-$DEFAULT_OPUS_MODEL}"
77
+ OPUS_MODEL_NAME="${ANTHROPIC_DEFAULT_OPUS_MODEL_NAME:-$OPUS_MODEL}"
78
+ OPUS_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION:-Subconscious default model}"
79
+ SONNET_MODEL="${ANTHROPIC_DEFAULT_SONNET_MODEL:-$DEFAULT_SONNET_MODEL}"
80
+ SONNET_MODEL_NAME="${ANTHROPIC_DEFAULT_SONNET_MODEL_NAME:-$SONNET_MODEL}"
81
+ SONNET_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION:-Subconscious TIM Qwen 3.6 27B}"
82
+ HAIKU_MODEL="${ANTHROPIC_DEFAULT_HAIKU_MODEL:-$DEFAULT_HAIKU_MODEL}"
83
+ HAIKU_MODEL_NAME="${ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME:-$HAIKU_MODEL}"
84
+ HAIKU_MODEL_DESCRIPTION="${ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION:-Subconscious DeepSeek V4 Flash Marathon}"
85
+ COMMAND="install"
86
+
87
+ usage() {
88
+ cat <<'EOF'
89
+ Usage:
90
+ subc claude status
91
+ subc claude uninstall
92
+ subc claude help
93
+
94
+ Claude Code is launch-only: subc claude. Uninstall removes leftover
95
+ ~/.claude/subconscious-gateway.env from older persistent setup.
96
+ EOF
97
+ }
98
+
99
+ while [[ $# -gt 0 ]]; do
100
+ case "$1" in
101
+ install|use|env|unset|uninstall|status|help)
102
+ COMMAND="$1"
103
+ shift
104
+ ;;
105
+ --gateway-url)
106
+ GATEWAY_URL="${2:-}"
107
+ shift 2
108
+ ;;
109
+ --api-key)
110
+ API_KEY="${2:-}"
111
+ shift 2
112
+ ;;
113
+ --model)
114
+ MODEL="${2:-}"
115
+ shift 2
116
+ ;;
117
+ --compact-window)
118
+ COMPACT_WINDOW="${2:-}"
119
+ shift 2
120
+ ;;
121
+ --max-context-tokens)
122
+ MAX_CONTEXT_TOKENS="${2:-}"
123
+ shift 2
124
+ ;;
125
+ -h|--help)
126
+ usage
127
+ exit 0
128
+ ;;
129
+ --)
130
+ shift
131
+ break
132
+ ;;
133
+ *)
134
+ echo "unknown argument: $1" >&2
135
+ usage >&2
136
+ exit 1
137
+ ;;
138
+ esac
139
+ done
140
+
141
+ # Optional CLAUDE_GATEWAY_URL in shared .env overrides GATEWAY_URL for Claude only.
142
+ resolve_claude_gateway_url() {
143
+ printf '%s' "${CLAUDE_GATEWAY_URL:-$GATEWAY_URL}"
144
+ }
145
+
146
+ write_env() {
147
+ local effective_gateway_url
148
+ effective_gateway_url="$(resolve_claude_gateway_url)"
149
+ mkdir -p "$CLAUDE_DIR"
150
+ umask 077
151
+ cat >"$ENV_FILE" <<EOF
152
+ # Generated by subc — do not commit secrets.
153
+ export ANTHROPIC_BASE_URL="${effective_gateway_url}"
154
+ export ANTHROPIC_AUTH_TOKEN="${API_KEY}"
155
+ export ANTHROPIC_MODEL="${MODEL}"
156
+ export ANTHROPIC_SMALL_FAST_MODEL="${MODEL}"
157
+ export ANTHROPIC_DEFAULT_OPUS_MODEL="${OPUS_MODEL}"
158
+ export ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="${OPUS_MODEL_NAME}"
159
+ export ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="${OPUS_MODEL_DESCRIPTION}"
160
+ export ANTHROPIC_DEFAULT_SONNET_MODEL="${SONNET_MODEL}"
161
+ export ANTHROPIC_DEFAULT_SONNET_MODEL_NAME="${SONNET_MODEL_NAME}"
162
+ export ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="${SONNET_MODEL_DESCRIPTION}"
163
+ export ANTHROPIC_DEFAULT_HAIKU_MODEL="${HAIKU_MODEL}"
164
+ export ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="${HAIKU_MODEL_NAME}"
165
+ export ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="${HAIKU_MODEL_DESCRIPTION}"
166
+ export CLAUDE_CODE_SUBAGENT_MODEL="${MODEL}"
167
+ export CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS}"
168
+ export CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH="${MAX_SUBAGENT_SPAWN_DEPTH}"
169
+ export CLAUDE_CODE_AUTO_COMPACT_WINDOW="${COMPACT_WINDOW}"
170
+ export CLAUDE_CODE_MAX_CONTEXT_TOKENS="${MAX_CONTEXT_TOKENS}"
171
+ export CLAUDE_CODE_ENABLE_TELEMETRY=1
172
+ export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
173
+ # Claude Code purpose attribution only (api_request → /v1/logs):
174
+ # https://code.claude.com/docs/en/monitoring-usage#api-request-event
175
+ export OTEL_LOGS_EXPORTER=otlp
176
+ export OTEL_EXPORTER_OTLP_PROTOCOL=http/json
177
+ export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT="${effective_gateway_url%/}/v1/logs"
178
+ export OTEL_EXPORTER_OTLP_HEADERS="x-api-key=${API_KEY}"
179
+ export OTEL_EXPORTER_OTLP_TIMEOUT=2000
180
+ export OTEL_LOGS_EXPORT_INTERVAL=2000
181
+ EOF
182
+ chmod 600 "$ENV_FILE"
183
+ }
184
+
185
+ print_env_exports() {
186
+ if [[ ! -f "$ENV_FILE" ]]; then
187
+ echo "env file not found: $ENV_FILE" >&2
188
+ echo "Launch Claude with: subc claude" >&2
189
+ return 1
190
+ fi
191
+ cat "$ENV_FILE"
192
+ }
193
+
194
+ print_env_unsets() {
195
+ cat <<'EOF'
196
+ unset ANTHROPIC_BASE_URL
197
+ unset ANTHROPIC_AUTH_TOKEN
198
+ unset ANTHROPIC_MODEL
199
+ unset ANTHROPIC_SMALL_FAST_MODEL
200
+ unset ANTHROPIC_DEFAULT_OPUS_MODEL
201
+ unset ANTHROPIC_DEFAULT_OPUS_MODEL_NAME
202
+ unset ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION
203
+ unset ANTHROPIC_DEFAULT_SONNET_MODEL
204
+ unset ANTHROPIC_DEFAULT_SONNET_MODEL_NAME
205
+ unset ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION
206
+ unset ANTHROPIC_DEFAULT_HAIKU_MODEL
207
+ unset ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME
208
+ unset ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION
209
+ unset CLAUDE_CODE_SUBAGENT_MODEL
210
+ unset CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS
211
+ unset CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH
212
+ unset CLAUDE_CODE_AUTO_COMPACT_WINDOW
213
+ unset CLAUDE_CODE_MAX_CONTEXT_TOKENS
214
+ unset CLAUDE_CODE_ENABLE_TELEMETRY
215
+ unset CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC
216
+ unset OTEL_LOGS_EXPORTER
217
+ unset OTEL_EXPORTER_OTLP_PROTOCOL
218
+ unset OTEL_EXPORTER_OTLP_LOGS_ENDPOINT
219
+ unset OTEL_EXPORTER_OTLP_HEADERS
220
+ unset OTEL_EXPORTER_OTLP_TIMEOUT
221
+ unset OTEL_LOGS_EXPORT_INTERVAL
222
+ EOF
223
+ }
224
+
225
+ status() {
226
+ echo "scope: user"
227
+ echo "claude dir: $CLAUDE_DIR"
228
+ echo "env file: $ENV_FILE"
229
+ if [[ -f "$ENV_FILE" ]]; then
230
+ # shellcheck disable=SC1090
231
+ source "$ENV_FILE"
232
+ echo "gateway: ${ANTHROPIC_BASE_URL:-unset}"
233
+ if [[ -n "${ANTHROPIC_AUTH_TOKEN:-}" ]]; then
234
+ echo "api key: set (${#ANTHROPIC_AUTH_TOKEN} chars)"
235
+ else
236
+ echo "api key: unset"
237
+ fi
238
+ echo "model: ${ANTHROPIC_MODEL:-unset}"
239
+ echo "model picker: ${ANTHROPIC_DEFAULT_OPUS_MODEL_NAME:-unset}, ${ANTHROPIC_DEFAULT_SONNET_MODEL_NAME:-unset}, ${ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME:-unset}"
240
+ echo "max concurrent subagents: ${CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS:-unset}"
241
+ echo "max subagent spawn depth: ${CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH:-unset}"
242
+ echo "compact window: ${CLAUDE_CODE_AUTO_COMPACT_WINDOW:-unset}"
243
+ echo "max context tokens: ${CLAUDE_CODE_MAX_CONTEXT_TOKENS:-unset}"
244
+ else
245
+ echo "env file: missing"
246
+ echo "Launch Claude with: subc claude"
247
+ fi
248
+ }
249
+
250
+ case "$COMMAND" in
251
+ install)
252
+ if [[ -z "$GATEWAY_URL" || -z "$API_KEY" ]]; then
253
+ echo "--gateway-url and --api-key are required for install" >&2
254
+ exit 1
255
+ fi
256
+ write_env
257
+ echo "Wrote leftover env file $ENV_FILE"
258
+ echo "Launch Claude with: subc claude"
259
+ ;;
260
+ use)
261
+ if [[ ! -f "$ENV_FILE" ]]; then
262
+ echo "env file not found: $ENV_FILE" >&2
263
+ echo "Launch Claude with: subc claude" >&2
264
+ exit 1
265
+ fi
266
+ # shellcheck disable=SC1090
267
+ source "$ENV_FILE"
268
+ if ! command -v claude >/dev/null 2>&1; then
269
+ echo "claude CLI not found in PATH" >&2
270
+ exit 1
271
+ fi
272
+ exec claude "$@"
273
+ ;;
274
+ env)
275
+ print_env_exports
276
+ ;;
277
+ unset)
278
+ print_env_unsets
279
+ ;;
280
+ uninstall)
281
+ rm -f "$ENV_FILE"
282
+ echo "Removed $ENV_FILE"
283
+ ;;
284
+ status)
285
+ status
286
+ ;;
287
+ help)
288
+ usage
289
+ ;;
290
+ esac