@cartanova/qgrid-cli 2.3.8 → 2.3.9

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.
Files changed (29) hide show
  1. package/README.ko.md +131 -0
  2. package/README.md +60 -44
  3. package/bundle/web-dist/client/assets/{index-OQd6CclQ.js → index-Cj1iWi5i.js} +3 -3
  4. package/bundle/web-dist/client/assets/{logs-8T91eoLY.js → logs-DvGWhZTu.js} +1 -1
  5. package/bundle/web-dist/client/assets/{routes--GqHRT2A.js → routes-B_xvkM-J.js} +1 -1
  6. package/bundle/web-dist/client/assets/{show-cHMucIDC.js → show-C6W3ywZz.js} +1 -1
  7. package/bundle/web-dist/client/assets/{tokens-BXAJUeCJ.js → tokens-CxjeN72g.js} +1 -1
  8. package/bundle/web-dist/client/index.html +1 -1
  9. package/bundle/web-dist/server/entry-server.generated.js +1 -1
  10. package/package.json +7 -3
  11. package/postinstall.mjs +119 -0
  12. package/skills/qgrid/SKILL.md +54 -0
  13. package/skills/qgrid/agents/openai.yaml +4 -0
  14. package/skills/qgrid/references/ai-sdk-provider-contract.md +100 -0
  15. package/skills/qgrid/references/anthropic-claude-code-runtime.md +170 -0
  16. package/skills/qgrid/references/cli-env-and-server-boot.md +66 -0
  17. package/skills/qgrid/references/decision-rationale.md +179 -0
  18. package/skills/qgrid/references/docs-workflow.md +32 -0
  19. package/skills/qgrid/references/openai-codex-runtime.md +153 -0
  20. package/skills/qgrid/references/prompt-cache-and-usage.md +101 -0
  21. package/skills/qgrid/references/provider-runtime-differences.md +54 -0
  22. package/skills/qgrid/references/repo-map.md +37 -0
  23. package/skills/qgrid/references/request-log-run-lifecycle.md +76 -0
  24. package/skills/qgrid/references/sonamu-api-web-flow.md +47 -0
  25. package/skills/qgrid/references/token-auth-quota-lifecycle.md +205 -0
  26. package/skills/qgrid/references/tool-calling-and-multiturn.md +144 -0
  27. package/skills/qgrid/references/verification-and-debugging.md +193 -0
  28. package/bundle/dist/migrations/20260705140615_alter_request_log_steps_alter1.js +0 -14
  29. package/bundle/src/migrations/20260705140615_alter_request_log_steps_alter1.ts +0 -13
@@ -0,0 +1,119 @@
1
+ import { existsSync } from "node:fs";
2
+ import { cp, mkdir, rm, symlink } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const packageDir = path.dirname(fileURLToPath(import.meta.url));
8
+ const sourceSkillsDir = path.join(packageDir, "skills", "qgrid");
9
+
10
+ function hasArg(name) {
11
+ return process.argv.slice(2).includes(name);
12
+ }
13
+
14
+ function findProjectRoot(startDir) {
15
+ let current = path.resolve(startDir);
16
+ let packageJsonRoot = null;
17
+
18
+ while (true) {
19
+ if (
20
+ existsSync(path.join(current, "pnpm-workspace.yaml")) ||
21
+ existsSync(path.join(current, ".git"))
22
+ ) {
23
+ return current;
24
+ }
25
+
26
+ if (!packageJsonRoot && existsSync(path.join(current, "package.json"))) {
27
+ packageJsonRoot = current;
28
+ }
29
+
30
+ const parent = path.dirname(current);
31
+ if (parent === current) return packageJsonRoot ?? path.resolve(startDir);
32
+ current = parent;
33
+ }
34
+ }
35
+
36
+ function defaultProjectRoot() {
37
+ if (process.env.QGRID_SKILLS_CWD) return findProjectRoot(process.env.QGRID_SKILLS_CWD);
38
+ if (process.env.INIT_CWD) return findProjectRoot(process.env.INIT_CWD);
39
+
40
+ const cwd = process.cwd();
41
+ if (cwd.includes(`${path.sep}node_modules${path.sep}`)) return null;
42
+ return findProjectRoot(cwd);
43
+ }
44
+
45
+ function defaultTargets() {
46
+ const isGlobalInstall =
47
+ process.env.npm_config_global === "true" || process.env.npm_config_location === "global";
48
+
49
+ if (hasArg("--global") || isGlobalInstall) {
50
+ const codexHome = process.env.CODEX_HOME
51
+ ? path.resolve(process.env.CODEX_HOME)
52
+ : path.join(os.homedir(), ".codex");
53
+ const claudeHome = process.env.CLAUDE_HOME
54
+ ? path.resolve(process.env.CLAUDE_HOME)
55
+ : path.join(os.homedir(), ".claude");
56
+ return [
57
+ { label: "Codex", target: path.join(codexHome, "skills", "qgrid"), useSymlink: false },
58
+ { label: "Claude Code", target: path.join(claudeHome, "skills", "qgrid"), useSymlink: false },
59
+ ];
60
+ }
61
+
62
+ const projectRoot = defaultProjectRoot();
63
+ if (!projectRoot) return null;
64
+
65
+ return [
66
+ {
67
+ label: "Codex",
68
+ target: path.join(projectRoot, ".agents", "skills", "qgrid"),
69
+ useSymlink: true,
70
+ },
71
+ {
72
+ label: "Claude Code",
73
+ target: path.join(projectRoot, ".claude", "skills", "qgrid"),
74
+ useSymlink: true,
75
+ },
76
+ ];
77
+ }
78
+
79
+ async function syncSkill({ label, target, useSymlink }) {
80
+ if (!existsSync(path.join(sourceSkillsDir, "SKILL.md"))) {
81
+ console.log("qgrid skill source not found in qgrid CLI package.");
82
+ return;
83
+ }
84
+
85
+ await rm(target, { recursive: true, force: true });
86
+ await mkdir(path.dirname(target), { recursive: true });
87
+
88
+ if (useSymlink) {
89
+ try {
90
+ await symlink(sourceSkillsDir, target, "dir");
91
+ console.log(`qgrid skill linked for ${label}: ${target}`);
92
+ return;
93
+ } catch (error) {
94
+ console.log(
95
+ `qgrid skill symlink failed for ${label}: ${error instanceof Error ? error.message : String(error)}`,
96
+ );
97
+ console.log("falling back to copy");
98
+ }
99
+ }
100
+
101
+ await cp(sourceSkillsDir, target, { recursive: true });
102
+ console.log(`qgrid skill copied for ${label}: ${target}`);
103
+ }
104
+
105
+ const targetConfigs = defaultTargets();
106
+
107
+ if (!targetConfigs) {
108
+ console.log("qgrid skill sync skipped: project root not found.");
109
+ process.exit(0);
110
+ }
111
+
112
+ try {
113
+ for (const targetConfig of targetConfigs) {
114
+ await syncSkill(targetConfig);
115
+ }
116
+ } catch (error) {
117
+ console.error(`qgrid skill sync failed: ${error instanceof Error ? error.message : String(error)}`);
118
+ process.exit(1);
119
+ }
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: qgrid
3
+ description: Work on the qgrid repository, an LLM subscription-token proxy with OpenAI Codex app-server workers, Anthropic Claude Code fresh-spawn runtime, AI SDK provider compatibility, Sonamu API/web generation, token routing, prompt-cache behavior, request logging, quota thresholds, and dashboard flows. Use when implementing, debugging, reviewing, or planning qgrid code, docs, migrations, provider integrations, CLI/runtime behavior, request logs, or SDK behavior.
4
+ ---
5
+
6
+ # Qgrid
7
+
8
+ ## Start Here
9
+
10
+ Use this skill for qgrid repository work. Treat qgrid as a runtime-contract-heavy system: model input travels through the active AI SDK provider, Sonamu API, provider dispatcher, provider-specific runtime, response mapping, request logging, and dashboard display.
11
+
12
+ Before changing code, identify the affected path:
13
+
14
+ - Public AI SDK provider: read `references/ai-sdk-provider-contract.md`.
15
+ - CLI startup, env vars, server boot, OAuth callback URL: read `references/cli-env-and-server-boot.md`.
16
+ - OpenAI models or Codex worker/thread/cache behavior: read `references/openai-codex-runtime.md`.
17
+ - Anthropic models or Claude Code spawn/stream-json behavior: read `references/anthropic-claude-code-runtime.md`.
18
+ - Token registration, OAuth, token sync, active/inactive behavior, or quota thresholds: read `references/token-auth-quota-lifecycle.md`.
19
+ - Provider comparisons, routing, or cross-provider bugs: read `references/provider-runtime-differences.md`.
20
+ - Tool calling, AI SDK multi-step loops, or tool-call request logs: read `references/tool-calling-and-multiturn.md`.
21
+ - `sessionKey`, `threadCoord`, prompt cache metrics, usage accounting, or cost: read `references/prompt-cache-and-usage.md`.
22
+ - Design rationale, prior decisions, or "why is this feature shaped this way?": read `references/decision-rationale.md`.
23
+ - Dashboard changes: read `references/sonamu-api-web-flow.md`.
24
+ - Request log lifecycle, tool-call steps, telemetry/logger behavior: read `references/request-log-run-lifecycle.md`.
25
+ - Choosing tests, smoke scripts, or debugging common runtime errors: read `references/verification-and-debugging.md`.
26
+ - Project planning/review/documentation workflow: read `references/docs-workflow.md`.
27
+ - Repository orientation: read `references/repo-map.md`.
28
+
29
+ ## Setup Guardrails
30
+
31
+ When helping a user set up local `@cartanova/qgrid-ai-sdk`, `createQgridLogger`, or qgrid CLI-backed workflows, ensure request-log project naming is configured. Check for `QGRID_PROJECT_NAME` in the calling app/runtime environment or `projectName` in qgrid provider/logger config. If neither is present, ask the user for a stable project/workflow name or add the obvious repository/app name when the surrounding setup convention makes that appropriate.
32
+
33
+ Prefer `QGRID_PROJECT_NAME` as the project-wide default. Use config `projectName` only for a deliberate per-call/per-provider override. Do not add `projectName` or `project_name` under `providerOptions.qgrid`; current code does not read it there.
34
+
35
+ ## Non-Negotiable Boundaries
36
+
37
+ - Use `packages/ai-sdk` as the active public SDK surface.
38
+ - Treat `packages/sdk` as deprecated. Read it only for legacy context or migration clues. Do not add new examples or features on top of it unless explicitly asked for legacy work.
39
+ - Route provider models by prefix: `openai/*` goes to the OpenAI Codex runtime, `anthropic/*` goes to the Anthropic Claude Code runtime. Prefix-less model fallback is not implemented.
40
+ - Treat dashboard work as Sonamu API/model/generated-client/web work, not isolated frontend work.
41
+ - Keep OpenAI Codex built-in tools, apps, plugins, skills, web search, shell, and environment instruction blocks disabled unless the user explicitly asks for agentic Codex behavior.
42
+ - Treat OpenAI image generation as an opt-in Codex `image_generation` tool path. Inspect current code before modifying it; it is not a direct Images API call and its image cost is an estimate.
43
+
44
+ ## Verification
45
+
46
+ Choose verification by blast radius:
47
+
48
+ - Type/lint/format: `pnpm check`.
49
+ - Package tests: use the relevant package test command or targeted Vitest files.
50
+ - Provider runtime changes: run targeted tests for `packages/api/src/utils/providers/**` and, when practical, the relevant smoke script in `scripts/` or `packages/api/scripts/`.
51
+ - AI SDK changes: run `packages/ai-sdk` tests and inspect generated request payload behavior.
52
+ - Sonamu API/model changes: check generated files and both API and web consumers.
53
+
54
+ Do not rely on one provider's behavior to infer the other provider's behavior. OpenAI/Codex and Anthropic/Claude Code have different process lifetimes, cache behavior, usage accounting, and structured-output paths.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Qgrid"
3
+ short_description: "Develop and debug qgrid runtime contracts"
4
+ default_prompt: "Use $qgrid to implement or debug qgrid provider runtime behavior."
@@ -0,0 +1,100 @@
1
+ # AI SDK Provider Contract
2
+
3
+ Use this reference before changing `packages/ai-sdk`.
4
+
5
+ ## Active public surface
6
+
7
+ `packages/ai-sdk` is the active public SDK package. `packages/sdk` is deprecated and context-only.
8
+
9
+ qgrid's custom provider implements the AI SDK `LanguageModelV3` contract. General usage should follow the AI SDK docs and normal AI SDK APIs such as `generateText`, `streamText`, tools, structured output, and telemetry. Do not re-document generic AI SDK usage in qgrid-specific docs unless the behavior differs. qgrid docs and this skill should focus on qgrid-specific config, `providerOptions.qgrid`, request logging, runtime routing, cache/session behavior, and provider limitations.
10
+
11
+ For tool calling, qgrid intentionally follows the AI SDK interface while implementing provider calls through qgrid structured-output emulation. Read `tool-calling-and-multiturn.md` before changing tool behavior, `stopWhen`/multi-step behavior, or tool-call request logs.
12
+
13
+ Main files:
14
+
15
+ - `packages/ai-sdk/src/index.ts`: `qgrid()` provider implementation.
16
+ - `packages/ai-sdk/src/index.types.ts`: public config/options/types.
17
+ - `packages/ai-sdk/src/utils.ts`: prompt/history/tool conversion.
18
+ - `packages/ai-sdk/src/logger.ts`: telemetry logger integration.
19
+ - `packages/ai-sdk/src/qgrid.constant.ts`: defaults and warnings.
20
+
21
+ ## Provider config
22
+
23
+ `qgrid(modelId, config)` supports:
24
+
25
+ - `serverUrl`: default `process.env.QGRID_URL`, then `http://localhost:44900`.
26
+ - `defaultEffort`: default `low`.
27
+ - `projectName`: default `process.env.QGRID_PROJECT_NAME`.
28
+
29
+ Strongly recommend setting `QGRID_PROJECT_NAME` in the environment for real workloads. The config-level `projectName` override is valid, but the env var is the preferred project-wide default. It is stored as `request_logs.project_name` and makes high-volume request logs usable: operators can filter by project/workflow, identify which task produced which request, compare token/cache/cost/TTFT metrics by workload, and debug noisy callers without scanning prompts manually.
30
+
31
+ Use camelCase `projectName` in TypeScript and qgrid API payloads. `project_name` is the database/Sonamu request-log field name, not an AI SDK provider option.
32
+
33
+ Setup agents should treat a missing project label as an actionable configuration gap. When installing or wiring qgrid for a local app, inspect the target app's env/config. If neither `QGRID_PROJECT_NAME` nor qgrid provider/logger config `projectName` is present, ask the user for a stable project or workflow name, then add it using the project's normal env/config pattern. A repo or package name is an acceptable default only when it is clearly the user's intended workload label.
34
+
35
+ ## Provider options
36
+
37
+ qgrid-specific behavior is controlled through `providerOptions.qgrid`. Explain these options precisely because they are qgrid's extension point beyond normal AI SDK usage.
38
+
39
+ `providerOptions.qgrid` supports:
40
+
41
+ - `sessionKey`: OpenAI thread reuse key. Disabled for Anthropic models.
42
+ - `effort`
43
+ - `verbosity`: OpenAI/Codex route only.
44
+ - `reasoningSummary`: OpenAI/Codex route only.
45
+ - `serviceTier`: OpenAI/Codex route only.
46
+ - `fallbackModels`: reserved for future fallback routing.
47
+ - `imageGeneration`: OpenAI/Codex non-stream only. Enables Codex's built-in `image_generation` tool for that request.
48
+ - `imageGenerationOptions`: optional image quality/size hints and cost-estimation basis. Current supported values are `quality: "low" | "medium" | "high"` and `size: "1024x1024" | "1024x1536" | "1536x1024"`.
49
+
50
+ `providerOptions.qgrid` does not currently support `projectName` or `project_name`. Prefer `QGRID_PROJECT_NAME` for the default project label; use config `projectName` only when a caller needs to override that default.
51
+
52
+ ## Request construction
53
+
54
+ The provider sends `POST /api/qgrid/query` for generate and `prepareStream` plus SSE for stream.
55
+
56
+ Payload responsibilities:
57
+
58
+ - Extract current prompt, system prompt, and history from AI SDK prompt messages.
59
+ - Convert AI SDK function tools to qgrid tools.
60
+ - Send `jsonSchema` only when no tools are present and response format top-level schema is `object`.
61
+ - Send `history` as JSON string when prior messages exist.
62
+ - Send `projectName` when configured.
63
+ - Use `logMode: "run"` for tool-call loops.
64
+ - Preserve and resend `runContext` for tool-call follow-ups.
65
+ - Store/resend OpenAI `threadCoord` by `sessionKey`.
66
+ - Send `imageGeneration` and `imageGenerationOptions` when configured.
67
+
68
+ Tools and `jsonSchema` cannot be used together at qgrid dispatcher level.
69
+
70
+ When tools are present, qgrid sends tool definitions to the server as `tools`; it does not send them to OpenAI or Anthropic as native provider tools. The server converts them into a strict structured-output schema and maps the model's structured result back into AI SDK `tool-call` content.
71
+
72
+ Image generation is different from AI SDK client tools: it is an opt-in Codex-hosted tool exposed by qgrid through `providerOptions.qgrid.imageGeneration`. Use `generateText`; `streamText` rejects image generation before opening the stream.
73
+
74
+ ## Response mapping
75
+
76
+ qgrid response content maps to AI SDK content:
77
+
78
+ - qgrid `text` -> AI SDK text content.
79
+ - qgrid `tool-call` -> AI SDK tool-call content.
80
+ - qgrid `image` -> AI SDK file content with `mediaType: "image/png"`.
81
+
82
+ `finishReason` maps `tool-calls` when qgrid returns tool calls.
83
+
84
+ When `imageGeneration` was requested and the server returns no image part, the AI SDK provider throws a version-skew/error guard instead of silently accepting text-only output.
85
+
86
+ Usage maps qgrid standard usage into AI SDK V3 usage:
87
+
88
+ - `inputTokens.total = input_tokens`
89
+ - `inputTokens.cacheRead = cache_read_input_tokens`
90
+ - `inputTokens.cacheWrite = cache_creation_input_tokens`
91
+ - `inputTokens.noCache = max(input - cacheRead - cacheWrite, 0)`
92
+ - `outputTokens.total = output_tokens`
93
+
94
+ ## Anthropic sessionKey guard
95
+
96
+ Do not store or replay `sessionKey` thread coordinates for `anthropic/*` models. Tests cover this because Anthropic fresh-spawn runtime cannot safely use Codex-style thread reuse.
97
+
98
+ ## Logger integration
99
+
100
+ `createQgridLogger` records external provider calls into qgrid request logs. It skips qgrid provider calls to avoid double-logging. When changing logger behavior, preserve stale-run fallback because AI SDK telemetry lacks a reliable error hook for all failure modes.
@@ -0,0 +1,170 @@
1
+ # Anthropic Claude Code Runtime
2
+
3
+ Use this reference before changing Anthropic provider behavior, Claude Code spawn args/env, stream-json adaptation, structured output, 1M context behavior, token routing, OAuth refresh, or quota handling.
4
+
5
+ ## Contents
6
+
7
+ - Process model
8
+ - Token routing
9
+ - OAuth refresh
10
+ - Spawn args
11
+ - Spawn env
12
+ - Config isolation
13
+ - Input adaptation
14
+ - Output adaptation
15
+ - Structured output
16
+ - 1M context
17
+
18
+ ## Process model
19
+
20
+ Anthropic uses fresh Claude Code process spawn per request. It does not use a persistent worker pool.
21
+
22
+ - Dispatcher: `packages/api/src/utils/providers/anthropic/anthropic-dispatcher.ts`.
23
+ - Session runner: `packages/api/src/utils/providers/anthropic/claude-session.ts`.
24
+ - Stream adapter: `packages/api/src/utils/providers/anthropic/stream-json-adapter.ts`.
25
+ - Constants/model normalization: `packages/api/src/utils/providers/anthropic/anthropic-constants.ts`.
26
+ - Process command: `claude -p ...`.
27
+ - Each request gets a fresh UUID `--session-id`.
28
+ - `workerId` is `tokenId`.
29
+ - `epoch` is always `0`.
30
+
31
+ The emitted `threadCoord` lets qgrid keep a shared response shape, but AI SDK disables `sessionKey` storage/replay for `anthropic/*` models. Do not implement Anthropic cache by pretending Claude sessions are reused unless the runtime design changes.
32
+
33
+ ## Token routing
34
+
35
+ Anthropic tokens live in an in-memory `Map<tokenId, PooledToken>`.
36
+
37
+ - Startup loads active Anthropic tokens from DB.
38
+ - Token subscriber events add/update/remove entries.
39
+ - Periodic reconcile replaces pool contents from active DB rows.
40
+ - Request selection is least-used plus round-robin tie-break.
41
+ - Request count is incremented before awaiting execution so concurrent requests spread across tokens.
42
+
43
+ Quota threshold:
44
+
45
+ - `quota_threshold` is checked through Anthropic quota usage.
46
+ - Lookup failure is fail-open.
47
+ - If all eligible tokens exceed threshold, throw `QuotaThresholdExceededError`.
48
+
49
+ ## OAuth refresh
50
+
51
+ Before spawning Claude, qgrid refreshes access tokens when expiration is within 60 seconds and a refresh token exists.
52
+
53
+ Refresh is attempted through `QgridFrame.refreshToken` with provider set to `anthropic`. Refresh failure is logged and the current access token is still tried.
54
+
55
+ ## Spawn args
56
+
57
+ `buildClaudeArgs` constructs Claude Code flags:
58
+
59
+ ```text
60
+ claude -p
61
+ --tools ""
62
+ --allowed-tools StructuredOutput # only when jsonSchema exists
63
+ --disallowedTools Monitor PushNotification RemoteTrigger
64
+ --input-format stream-json
65
+ --output-format stream-json
66
+ --verbose
67
+ --include-partial-messages # streaming path only
68
+ --permission-mode bypassPermissions
69
+ --setting-sources project
70
+ --model <canonical-model-or-1m-suffix>
71
+ --system-prompt <text> # small system prompt
72
+ --system-prompt-file <path> # large system prompt
73
+ --thinking disabled
74
+ --effort <effort-or-low>
75
+ --disable-slash-commands
76
+ --session-id <uuid>
77
+ --json-schema <schema> # only when jsonSchema exists
78
+ ```
79
+
80
+ Important details:
81
+
82
+ - `--tools ""` blocks normal tools. With structured output, only `StructuredOutput` is allowed.
83
+ - `--setting-sources project` plus seeded settings isolates user configuration.
84
+ - `--system-prompt` or `--system-prompt-file` is always supplied. Omitting it would allow Claude Code default system prompt injection.
85
+ - Large system prompts over 64 KiB are written to a temporary file to avoid argv `E2BIG`.
86
+ - `--thinking disabled`, `MAX_THINKING_TOKENS=0`, and adaptive thinking env suppression keep thinking off.
87
+
88
+ ## Spawn env
89
+
90
+ qgrid builds a fresh env whitelist. Do not spread `process.env` into Claude child env.
91
+
92
+ Included env:
93
+
94
+ - `PATH`
95
+ - `TMPDIR`
96
+ - `CLAUDE_CODE_OAUTH_TOKEN`
97
+ - `CLAUDE_CONFIG_DIR`
98
+ - `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1`
99
+ - `CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1`
100
+ - `CLAUDE_CODE_DISABLE_CLAUDE_MDS=1`
101
+ - `CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1`
102
+ - `CLAUDE_CODE_DISABLE_BUNDLED_SKILLS=1`
103
+ - `CLAUDE_CODE_DISABLE_WORKFLOWS=1`
104
+ - `CLAUDE_CODE_ATTRIBUTION_HEADER=0`
105
+ - `MAX_THINKING_TOKENS=0`
106
+ - `CLAUDE_CODE_DISABLE_1M_CONTEXT=1` when model does not support qgrid's 1M path
107
+ - `MAX_STRUCTURED_OUTPUT_RETRIES` for structured output only
108
+
109
+ Never pass `ANTHROPIC_API_KEY` or inherited auth env vars to child processes. OAuth must flow through `CLAUDE_CODE_OAUTH_TOKEN`.
110
+
111
+ ## Config isolation
112
+
113
+ - Shared cwd: `/tmp/qgrid-anthropic`.
114
+ - Project settings file: `/tmp/qgrid-anthropic/.claude/settings.json`, written as `{}`.
115
+ - Per-token config dir: `/tmp/qgrid-anthropic-config/${tokenId}`.
116
+ - qgrid writes `{}` to both `.claude.json` and `settings.json` inside the per-token config dir before each run.
117
+
118
+ This blocks user-scope Claude settings, hooks, memory, and token cross-contamination as much as the current Claude Code interface allows.
119
+
120
+ ## Input adaptation
121
+
122
+ qgrid sends Claude stdin as JSONL with `--input-format stream-json`.
123
+
124
+ - Current input is the only executable user line.
125
+ - Prior conversation history is flattened into a single assistant context line prefixed with `Prior conversation context:`.
126
+ - Function calls and function outputs from AI SDK history are flattened into text.
127
+ - Each JSONL line is decorated with `session_id`, `uuid`, and `parent_tool_use_id: null`.
128
+
129
+ This is not equivalent to persistent Claude session reuse. It is full-history replay through a fresh process.
130
+
131
+ ## Output adaptation
132
+
133
+ Claude stdout JSONL is parsed by `stream-json-adapter.ts`.
134
+
135
+ - Text mode streams `text_delta`.
136
+ - Structured mode streams `input_json_delta` and preserves `StructuredOutput` tool input as final text.
137
+ - `result` lines provide final text, usage, duration, cost, subtype, and terminal reason.
138
+ - Non-success subtype, `is_error`, or `terminal_reason: model_error` is treated as an error.
139
+ - Quota exhaustion is detected when text starts with `You've hit`.
140
+
141
+ Anthropic native usage categories are mutually exclusive. qgrid normalizes them into its provider-standard shape by setting:
142
+
143
+ ```text
144
+ inputTokens = input_tokens + cache_creation_input_tokens + cache_read_input_tokens
145
+ cachedInputTokens = cache_read_input_tokens
146
+ cacheCreationInputTokens = cache_creation_input_tokens
147
+ ```
148
+
149
+ ## Structured output
150
+
151
+ qgrid strictifies schemas before provider dispatch. Claude Code `--json-schema` is not grammar-constrained decoding; it is a `StructuredOutput` tool plus post-validation behavior. Keep schemas strict and preserve error signaling for failed structured-output attempts.
152
+
153
+ `MAX_STRUCTURED_OUTPUT_RETRIES` defaults to `1` for structured Anthropic calls and is clamped to at least 1. Avoid setting it to 0; Claude Code can fail before emitting a useful attempt.
154
+
155
+ ## 1M context
156
+
157
+ Model normalization strips provider prefix and `[1m]` for canonical model/cost keys.
158
+
159
+ qgrid's measured 1M support set currently includes:
160
+
161
+ - `claude-sonnet-4-6`
162
+ - `claude-opus-4-6`
163
+ - `claude-opus-4-8`
164
+
165
+ Models requiring CLI `[1m]` suffix:
166
+
167
+ - `claude-sonnet-4-6`
168
+ - `claude-opus-4-6`
169
+
170
+ Unsupported `[1m]` suffixes throw early.
@@ -0,0 +1,66 @@
1
+ # CLI, Env, And Server Boot
2
+
3
+ Use this reference for qgrid startup, configuration, and runtime-facing environment variables.
4
+
5
+ ## CLI options
6
+
7
+ - `--db <url>`: PostgreSQL URL in `postgres://user:password@host:port/dbname` or `postgresql://...` form. Parsed by `packages/cli/src/cli.ts` and copied into `QGRID_DB_*` env vars before server boot.
8
+ - `-p, --port <port>`: server port. Default `44900`. The CLI validates the port and refuses to start if it is already in use.
9
+ - `--skip-update`: skip qgrid CLI self-update check.
10
+
11
+ The CLI also ensures runtime CLIs are installed/current enough:
12
+
13
+ - `codex` from `@openai/codex`, required for OpenAI tokens.
14
+ - `claude` from `@anthropic-ai/claude-code`, required for Anthropic tokens.
15
+
16
+ ## Server env vars agents should know
17
+
18
+ | Env | Default | Meaning |
19
+ |---|---:|---|
20
+ | `QGRID_DB_HOST` | `localhost` | PostgreSQL host. |
21
+ | `QGRID_DB_PORT` | `5432` | PostgreSQL port. |
22
+ | `QGRID_DB_USER` | `postgres` | PostgreSQL user. |
23
+ | `QGRID_DB_PASSWORD` | `postgres` | PostgreSQL password. |
24
+ | `QGRID_DB_NAME` | `qgrid` | PostgreSQL database. |
25
+ | `HOST` | `localhost` | Sonamu server listen host when running API directly. |
26
+ | `PORT` | `44900` | Sonamu server listen port. In CLI mode this is derived from `--port`, not read as user input. |
27
+ | `QGRID_PUBLIC_BASE_URL` | empty | Public base URL used to construct Anthropic OAuth callback URL. If unset, callback defaults to `http://localhost:${PORT}/callback`. |
28
+ | `PROJECT_NAME` | `Qgrid` | Sonamu project name. Not the same as request log `projectName`. |
29
+
30
+ Do not treat CLI bundle bootstrapping internals as user-facing qgrid configuration.
31
+
32
+ ## SDK/client env vars
33
+
34
+ | Env | Default | Meaning |
35
+ |---|---:|---|
36
+ | `QGRID_URL` | `http://localhost:44900` | Server URL used by `@cartanova/qgrid-ai-sdk` and logger integration. |
37
+ | `QGRID_PROJECT_NAME` | empty | Request log project name sent by the AI SDK provider/logger unless overridden in config. Configure this in the calling app or agent runtime environment, not only in the qgrid server process. |
38
+
39
+ When helping a user set up qgrid locally, check for `QGRID_PROJECT_NAME` or config `projectName`. If absent, ask for a stable project/workflow label or add the obvious app/repo name when the setup context makes it unambiguous. This keeps request logs, metrics, and dashboard filters usable once traffic volume grows.
40
+
41
+ ## Provider runtime knobs
42
+
43
+ | Env | Default | Meaning |
44
+ |---|---:|---|
45
+ | `QGRID_WORKERS_PER_TOKEN` | `3` | OpenAI Codex workers per token. Capped at 5 in code. |
46
+ | `QGRID_OPENAI_THREAD_REUSE` | enabled | Set to `"false"` to disable OpenAI thread reuse and force cold thread behavior. |
47
+ | `MAX_STRUCTURED_OUTPUT_RETRIES` | `1` for structured Anthropic calls | Claude Code structured-output retry count, clamped to at least 1 by qgrid. |
48
+
49
+ ## Server boot lifecycle
50
+
51
+ On server start, `packages/api/src/sonamu.config.ts`:
52
+
53
+ 1. Loads `.env` from `packages/api/.env` when running API directly.
54
+ 2. Configures Sonamu database connection from `QGRID_DB_*`.
55
+ 3. Runs latest migrations from `packages/api/src/migrations`.
56
+ 4. Ensures PostgreSQL `tokens_changed` triggers.
57
+ 5. Starts `TokenSubscriber` for LISTEN/NOTIFY plus periodic reconcile.
58
+ 6. Starts `OpenAIDispatcher` and `AnthropicDispatcher`.
59
+ 7. Logs server URL and provider readiness counts.
60
+
61
+ On shutdown, it stops provider dispatchers and the token subscriber.
62
+
63
+ ## OAuth callbacks
64
+
65
+ - Anthropic OAuth uses `/callback` on the qgrid server. The callback URL is based on `QGRID_PUBLIC_BASE_URL` when set, otherwise localhost and `PORT`.
66
+ - OpenAI OAuth is handled by Codex app-server's own callback flow and completed through qgrid's OpenAI OAuth APIs.