Repository navigation
Conversation
…tion) Run the dev-kit agent on your own Claude Code subscription instead of a separately-billed API key, so ticket work and local extension development bill to the same place. The agent embeds the Claude Code CLI, so it can authenticate this way. It needs a long-lived token from `claude setup-token`, which has to be minted on the developer's own machine because it opens a browser — it is not the short-lived credential in the OS keychain, and not an sk-ant-api… API key. Those are three different auth schemes to the CLI. Requires the matching agent-side change (CLAUDE_CODE_OAUTH_TOKEN branch in core/agent_setup/llm_provider.py). Until an agent image carrying that ships, selecting this provider writes the right .env and the agent still falls through to Bedrock. - scripts/_provider_subscription.sh — the arm itself, factored out like the gateway arm: prompt, token-shape validation, and the load-bearing blanks. Subscription auth sits next-to-last in the agent's precedence chain, on purpose — a token exported in someone's shell must never displace a deliberately configured provider. The cost is that this arm has to clear ANTHROPIC_API_KEY and ANTHROPIC_BASE_URL, or either would win the chain and the token would never be read; same load-bearing blanking as bedrock-instance-role's AWS keys. - run.sh — menu option 5, --model subscription, --subscription-token, --subscription-model, the --reset key list, and the startup summary. - scripts/switch-llm.sh — switch to and from it in place, with the usual credential stashing. - docker-compose.yml, .env.example, docs/configuration.md, docs/cli-reference.md — passthrough and documentation. Two rough edges are caught rather than left to fail obscurely: an sk-ant-api… key pasted at the prompt gets a note (it would otherwise be sent as a bearer token and 401), and a us.anthropic.* inference-profile id carried over from a Bedrock run is replaced with the bare default (the first-party API rejects the prefix outright). Ticket titles are not generated on this path, as on the anthropic and gateway arms: the title LLM is Bedrock-only and no-ops without AWS credentials. Documented at each mention rather than fixed here. tests/test-provider-subscription.sh (11 checks) and tests/test-run-subscription-wiring.sh (11 checks) mirror the gateway suites; the existing gateway suites still pass (16 + 9). shellcheck clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…al dashboard UI The preset instructions didn't match what the OpenRouter dashboard actually shows, which made them unfollowable: - Presets live under the workspace sidebar, not Settings - The provider pin is the 'only' checklist — the form has three look-alike checklists (order/only/ignore) and the doc never said which one; ticking 'order' pins nothing - 'Allow fallbacks' is a separate dropdown much further down the form Rewritten around the three sections you actually touch, with a screenshot per step and the exact pinning JSON to expect after save. Section 4 gains the validated one-shot ./run.sh flag form and the model context windows (incl. glm-5.1 = 204800). Validated end-to-end 2026-09-22: preset created in the UI, pin confirmed via curl (provider: Nebius), dev kit started with --model gateway, agent turn on the ticket answered by the pinned provider. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
docs(hackday): rewrite Crusoe/Nebius OpenRouter steps to match the real dashboard UI
The three create calls in run.sh piped `curl -fsS ... | python3 json.load(sys.stdin)["data"]["id"]`. On a 4xx, -f makes curl print nothing, so the studio's explanation was discarded and the run ended with a bare `curl: (22) ... 400` plus a JSONDecodeError traceback from python reading empty stdin. Add scripts/_studio_api.sh with studio_create_id, which keeps the response body, prints the server's message/errors on stderr (tagged with the error code, e.g. license_limit_exceeded) and returns non-zero. An expired license now reports "This DuploCloud AI Studio instance's license has expired..." instead of a traceback. The workspace create is fatal since everything after it depends on the id; the permission set and group creates warn and continue, as before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
feat(agent-skills): add Codex skills symlink
.agents/skills -> ../.claude/skills (the Codex skills symlink added for GitHub Copilot/Codex support) was missing from FRAMEWORK_DIRS, so upgrade_dev_kit.sh silently skipped it on every already-adopted repo. Fresh clones got the symlink from git directly; upgrades never did. Verified against a simulated pre-PR adopter repo: the unpatched script exits 0 and reports "Framework upgraded" without ever creating .agents. With this fix it rsyncs the symlink in on the next upgrade run (the very first upgrade after this lands will still miss it once, since scripts/ itself only updates that same run — a second run picks it up). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
fix(scripts): include .agents in upgrade_dev_kit.sh framework dirs
Bump the vendored platform UI library from 0.2.0 to 0.3.0 for every sample and the extension skill template. The release is additive: no export the samples use was removed or changed shape. Pin ngx-monaco-editor-v2 to 22.0.4. Its 22.0.5 release raised the monaco-editor peer to ^0.56.0, which the library's ^0.55.1 excludes, so a fresh install failed with ERESOLVE. 22.0.4 is what the host portal resolves, and samples track the host. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Catalog every library export, how to import it, and which pieces work inside an extension remote (host services only via REMOTE_* tokens) - Add a need-to-component picker and recipes checked against the library source, covering the gotchas that fail without an error - Correct the error-handling reference: toasts do reach the host from a remote, though form errors are still reported inline - Link the new reference from the skill index and the authoring guide Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
chore: bump ng-common-lib to 0.3.0 and add a UI library reference
fix(run): surface studio API errors instead of a JSON traceback
Update STUDIO_TAG, AGENT_TAG, and UI_TAG to latest build references. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- run.sh, scripts/switch-llm.sh: initialize F_SUBSCRIPTION_TOKEN and F_SUBSCRIPTION_MODEL alongside the F_GATEWAY_* vars. Under set -u the arm died with "unbound variable" whenever a flag was omitted — after the stash step had already blanked the outgoing provider's keys, leaving .env half-migrated. - scripts/switch-llm.sh: namespace stash keys by provider (_STASH_<PROVIDER>_<KEY>). CLAUDE_MODEL (and AWS_REGION) are owned by several providers with incompatible id formats, so a flat _STASH_CLAUDE_MODEL handed e.g. a gateway's anthropic/… id to the subscription arm. Legacy flat stashes are still read for keys owned by a single provider; a flat stash of a shared key is ignored. - scripts/_provider_subscription.sh: the leftover-model guard now also catches gateway-namespaced ids (*/*), not just Bedrock profile ids. - tests: subscription suites run under set -euo pipefail like their callers; new tests/test-switch-llm-subscription.sh drives the real switch-llm.sh end to end in a throwaway root with a stub docker. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-subscription # Conflicts: # run.sh
… warn
docker compose resolves ${VAR:-} from the calling shell before .env, so an
ANTHROPIC_API_KEY or ANTHROPIC_BASE_URL exported in the user's shell defeated
the subscription arm's load-bearing .env blanks: it reached the agent, won
the precedence chain, and the subscription token was silently never used.
provider_subscription_configure now unsets them in-process (the helper is
sourced, so this affects only run.sh / switch-llm.sh, never the user's
shell), so the compose calls those scripts make are correct, and warns that
a manual `docker compose up` would still pick them up.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(run.sh): add a `subscription` LLM provider (Claude Code subscrip…
- run.sh / scripts/switch-llm.sh now provision Claude Sonnet 5 (claude-sonnet-5 direct Anthropic, us.anthropic.claude-sonnet-5 either Bedrock mode) as CLAUDE_MODEL, and add the matching Opus 5.5 id via a new comma-separated CLAUDE_EXTRA_MODELS env var. - scripts/register-llm.sh registers every id in CLAUDE_MODEL + CLAUDE_EXTRA_MODELS and makes the System LLM mapping exactly that set, with CLAUDE_MODEL as the default — so the ticket LLM picker offers Sonnet 5 (default) and Opus 5.5 side by side. The model-list build is bash 3.2 safe (macOS system bash) on every argument shape: blank CLAUDE_EXTRA_MODELS, a single positional id, several positional ids, and two ids from .env. - Gateway provider stays single-model (gateway model names are provider-specific) and its default moves to claude-sonnet-5. - The subscription provider (merged from dev/#1) gets the same treatment: SUBSCRIPTION_DEFAULT_MODEL moves to claude-sonnet-5, and provider_subscription_configure clears CLAUDE_EXTRA_MODELS for the same reason it already rejects a carried-over us.anthropic.* / gateway-namespaced CLAUDE_MODEL — the first-party API rejects those ids on either field. - Swept the retired claude-sonnet-4-6 / anthropic/claude-sonnet-4.6 ids out of scripts, docker-compose.yml fallback, .env.example, docs, and tests — no retired id remains in the repo outside hackday/'s third-party OpenRouter examples. Testing: all 5 suites pass, 58 checks — test-provider-gateway.sh 16/16, test-provider-subscription.sh 15/15, test-run-gateway-wiring.sh 9/9, test-run-subscription-wiring.sh 11/11, test-switch-llm-subscription.sh 7/7. docker compose config validates; bash -n clean on every touched script; ./run.sh --help renders. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
feat(scripts): default to Sonnet 5 and offer Opus 5.5 in the LLM picker
Replace the claude-opus-5-5 / us.anthropic.claude-opus-5-5 ids with claude-opus-5 / us.anthropic.claude-opus-5 in run.sh, switch-llm.sh, .env.example and the docs, so the ticket LLM picker offers Sonnet 5 (default) alongside Opus 5. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fix(scripts): use claude-opus-5 as the extra picker model
The subscription arm blanked CLAUDE_EXTRA_MODELS by copying the gateway
arm's rationale ("gateways name models their own way"). That reasoning
does not transfer: this path calls the first-party API with bare model
ids, exactly like the `anthropic` arm, so the picker should offer
claude-opus-5 the same way. Overwrite rather than carry over, since a
leftover us.anthropic.* id would be rejected by the first-party API.
Also trims the pasted token's leading/trailing whitespace. This is
normalization, not validation: no valid opaque bearer token has
whitespace at its edges, so it cannot turn away a good token whatever
shape tokens take next. Deliberately no length or format check — the
token's shape is not a documented contract, and rejecting a valid future
token with a confident error would be worse than the 401 it prevents.
Output trimmed to what the moment needs. The setup-token prompt no
longer re-argues a choice the user just made at the menu; the
Bedrock-only ticket-titles note and the exported-shell-var WARNING are
gone. The unset behind that warning is load-bearing and stays — it keeps
the scripts' own compose calls correct.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The product now handles usage-metrics consent inside the UI itself, so the dev kit no longer needs to ask, store a choice, or rewrite the served bundle: - run.sh: drop the --metrics/--no-metrics flags, the opt-out prompt, and the Metrics line in the ready banner - scripts/_metrics.sh, nginx/metrics-on.conf, nginx/metrics-off.conf: deleted - nginx/default.conf: drop the metrics.conf include; it's now a plain same-origin API proxy - docker-compose.yml: drop the METRICS_CONF volume mount - .env.example: drop DUPLO_USAGE_METRICS / METRICS_CONF - .gitleaksignore: deleted (its only entry covered the now-removed metrics-on.conf) - docs: PRIVACY.md, README.md, configuration.md, faq.md, cli-reference.md, getting-started/install.md, quickstart.md, docs/README.md, hackday/Installing DevKit.md updated to describe consent as an in-product UI setting Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…n-and-nginx feat(run.sh): remove usage-metrics opt-in prompt and nginx toggle
MongoDB 6.0 reached end of life on 2025-07-31. Move the dev kit off the EOL line and onto 7.0.14, matching the version the helpdesk-helm chart already pins, so local and deployed environments run the same server. 7.0 is supported until 2027-08-31. Verified that an existing 6.0 volume upgrades in place with no migration step: started mongo:6.0 (FCV 6.0), wrote data, then started mongo:7.0.14 against the same volume. It came up healthy, all data read back intact, and reads and writes both worked. The startup log is clean, reporting only the informational "current featureCompatibilityVersion: 6.0" line. FCV stays at 6.0, which is the supported steady state — 7.0-only on-disk features stay dormant, and nothing in the dev kit depends on them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
chore: bump devkit mongo from 6.0 to 7.0.14
A literal hostname in proxy_pass is resolved once when nginx loads its config and cached for the container's lifetime. Recreating the studio (any compose change to it, or to mongo, which it depends_on) moves its IP on the compose network, so the UI's nginx keeps proxying to the dead old address — every API call 502s, and since the login page uses two of those calls (SsoConfig, IsGoogleAuthenticationDisabled) to decide what to render, it comes up with no auth methods at all. Use Docker's embedded DNS (127.0.0.11) with a variable in proxy_pass so nginx re-resolves duplo-ai-studio on every request instead of once. Verified by force-recreating the studio onto a different IP without touching the UI container: proxied endpoints stayed 200 throughout. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
How it was verified
./run.sh --reset, then built and deployed a sample end to end./scripts/build-extension.shon the affected sample, then deployed it and created one in the UInpm ci && npm run buildin the affectedfrontend/./stop.sh --wipe && ./run.shfrom a clean slate/duplo-extensionand confirmed the guidance still matches realityOutput
Blast radius
.env.example— image tags or ports here are adopted into every user's.envon their next./run.shafter an upgrade. Say so plainly above.scripts/upgrade_dev_kit.shorscripts/init-project.sh— the adoption path.github/workflows/Checks
.env, tokens, keys, or customer identifiers in the diffdist/,node_modules/,**/bin/,**/obj/,backend/sdk-packages/ng-common-libtarball was added or bumped, itsNOTICEsits beside it