DESIGN-REVIEW.md is Fable's review of the v0.3.0 UI: token gaps and three
WCAG AA contrast failures, the modal/accessibility audit, and an IA
proposal that promotes the project from a sidebar card to a tabbed
main-area view.
ROADMAP.md covers Claude Code feature coverage — the five settings.json
keys currently surfaced, the gaps worth closing, the ones deliberately
skipped, the authentication handoff design, and phase sequencing.
Also published as an artifact for easier reading.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Permission modes: replaces the binary full_permissions flag with a
PermissionMode enum (Plan/Default/AcceptEdits/Bypass). Flag mapping is
defined once in PermissionMode::cli_args() and used by the terminal, the
web terminal, and the scheduler:
Plan -> --permission-mode plan
Default -> (no flag)
AcceptEdits -> --permission-mode acceptEdits
Bypass -> --dangerously-skip-permissions
Choices verified against `claude --permission-mode` on 2.1.226.
full_permissions is retained and effective_permission_mode() falls back
to it, so existing projects.json needs no migration.
Bug fix: triple-c-task-runner ran `claude -p ... --dangerously-skip-
permissions` unconditionally, ignoring the project's setting entirely.
It now reads TRIPLE_C_PERMISSION_MODE, which is injected into the
container, added to the reserved env blocklist, propagated through the
entrypoint's cron env filter, and tracked by a new
triple-c.permission-mode label so a change forces recreation.
Introspection: new commands/inspect_commands.rs exposes read-only views
into the container over docker exec — Claude sessions (parsed from
~/.claude/projects/<cwd>/<uuid>.jsonl), installed capabilities (skills,
agents, commands, hooks, plugins, natively-configured MCP servers), and
the triple-c-scheduler task list, logs and notifications.
Task/session ids are validated against a strict allowlist and every
parameterized call runs as a bare argv vector via bollard, so no shell
is involved. Stopped containers return empty results rather than errors.
No UI yet; that lands with the Project Home view.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Completes the removal begun in the previous commit.
Backend: deletes models/mcp_server.rs, storage/mcp_store.rs and
commands/mcp_commands.rs, the McpStore on AppState, the four IPC
handlers, Project::enabled_mcp_servers, build_mcp_servers_json(),
compute_mcp_fingerprint(), the MCP_SERVERS_JSON env injection, the
mcp-fingerprint label, and the whole MCP container lifecycle.
create_container() and container_needs_recreation() lose their
mcp_servers/network_name parameters.
Container: entrypoint.sh no longer merges MCP_SERVERS_JSON into
~/.claude.json. MCP_SERVERS_JSON stays in the reserved env blocklist.
Security: the Docker socket is no longer auto-mounted for stdio+Docker
MCP servers — it now mounts only when allow_docker_access is set.
Migration: old containers were created with
network_mode=triple-c-net-<projectId> and refuse to start once that
network is gone. docker/network.rs becomes docker/legacy_cleanup.rs with
label-driven, best-effort removal of leftover MCP containers and the
per-project network, called on both delete and recreate.
container_needs_recreation() now forces a rebuild for any container
carrying a non-empty triple-c.mcp-fingerprint label or attached to a
triple-c-net-* network, moving it onto the default bridge. Both can be
dropped a release later.
Docs: drops the MCP sections from README/HOW-TO-USE/TECHNICAL and adds a
short note pointing at Claude Code's native `claude mcp` / `/mcp` /
.mcp.json instead.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude Code manages MCP natively now (`claude mcp add/list/remove`,
`.mcp.json`, `/mcp`), so Triple-C's own MCP server library is redundant.
Deletes components/mcp/, hooks/useMcpServers.ts, the MCP sidebar tab and
rail icon, the per-project enable checkboxes on ProjectCard, the
mcpServers slice of the Zustand store, the four IPC wrappers, and the
McpServer/McpTransportType types.
Rust backend is untouched in this commit; the commands simply become
unreachable. Backend removal and the legacy container/network cleanup
follow separately.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
git rejects `--global` and `--file` together ("error: only one config
file at a time"), so the credential helper and user.name/user.email
were never written — /home/claude/.gitconfig was left nonexistent and
containers had no git identity or HTTPS token helper.
Drop `--global` and keep `--file /home/claude/.gitconfig`, which is the
intended target: the entrypoint runs as root at that point, so
`--global` would have resolved to /root/.gitconfig, and the existing
`chown claude:claude /home/claude/.gitconfig` already assumes the
--file path.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Capture the non-obvious implementation gotchas from PR #7
(terminal-layout-statusbar) in TECHNICAL.md: wrapper-vs-host xterm
padding, global StatusBar controls, recordingSessionIdRef transcript
pinning, active-only Jump-to-Current state, and the Zustand
object-merge rule for publishing action callbacks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The transform used `s,^\./,workspace/,`, which rewrites the workspace
*contents* (`./foo` -> `workspace/foo`) but leaves tar's root member as a
bare `./`. That `./` entry carries the source root's mode/mtime, and on
extraction tar stamps them onto the extraction directory itself.
Match the leading `.` instead (`s,^\.,workspace,`) so the root member is
renamed `./` -> `workspace`, giving the archive a proper `workspace/`
directory entry and no bare `./`. The extraction directory is left
untouched. Contents, hidden files, excludes, symlink targets and the
`flags=rh` hardlink handling are unchanged.
Verified in-container: archive top level is exactly `workspace/` +
`home-claude/`, no `./` member, node_modules excluded, extraction into a
0755 dir leaves it 0755, workspace/.git preserved.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review caught that `flags=r` disables rewriting of both symlink AND
hardlink target names. Leaving symlink targets alone is intended, but a
hardlink's stored target is an archive-internal reference to another
member's name — when member names become `workspace/...` but the
hardlink target stays `./hard_link`, extraction fails hard:
tar: workspace/file.txt: Cannot hard link to './hard_link':
No such file or directory
`flags=rh` rewrites regular member names and hardlink target names
together (keeping the pair consistent) while still leaving symlink
targets untouched. Verified in-container: extract exit 0, symlink target
preserved, hardlink pair shares one inode, nesting under workspace/ intact.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The backup archive placed the workspace at the archive root (`./...`)
while the sanitized home config sat under `home-claude/`. On extraction
the workspace files scattered loose into the extraction directory and
only `home-claude/` showed up as a distinct folder, so the backup read
as "config only, workspace missing" — and some archive viewers didn't
surface the root-level entries at all.
Add `--transform='flags=r;s,^\./,workspace/,'` so the workspace nests
under `workspace/`, parallel to `home-claude/`. `flags=r` scopes the
rewrite to member names only, leaving symlink targets (relative and
absolute) intact. Excludes still match the pre-transform names.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- F2: upload_host_file_to_container now reads the dropped file into a Vec
inside the blocking task and sizes the tar entry from those exact bytes,
rather than stat-then-stream where a file changing size between the
stat and the read could desync the tar header and silently corrupt the
archive. Still runs off the async worker; memory stays bounded by the
256 MiB drop cap.
- F4: the "Backup saved" confirmation now auto-clears after 8s (guarded
against clobbering a newer status message) instead of lingering in the
project card's status line indefinitely.
F1 (claimed AWS CLI regression from empty-env neutralization) was a false
positive: verified against aws-cli 2.35 that an empty AWS_ACCESS_KEY_ID is
treated as absent and botocore falls through to ~/.aws/credentials (the
call reached AWS and returned InvalidClientTokenId for the file's key, not
PartialCredentialsError). No change needed.
cargo check / tsc / vitest all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- L-e: route terminal file drops purely by a bounds hit-test instead of
the `active` flag. Inactive panes are display:none (zero-size rect) so
they never match; a zero-size guard makes that explicit. Correct for
the current tabbed layout and future-proof for split panes, where a
drop on a visible-but-unfocused pane previously matched no handler.
- L-f: stream the dropped file straight into the upload tar inside a
blocking task (new exec::upload_host_file_to_container) instead of
reading the whole file into a Vec and then re-packing it. Peak memory
drops from ~2x to ~1x the file size, and the synchronous file IO no
longer runs on the async worker.
cargo check / tsc / vitest all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- M1 (race): don't mount the host AWS dir for static-credential Bedrock.
sync_bedrock_credentials() is the sole writer of ~/.aws/credentials in
that mode, and mounting /tmp/.host-aws let the entrypoint's
`rm -rf ~/.aws; cp -a` race that write at startup (only when a global
aws_config_path was also set). Static keys + AWS_REGION env are
self-sufficient and don't need the host config, so skipping the mount
removes the dual-writer entirely.
- L-a: exit codes are now read via wait_for_exec_exit(), which polls
inspect_exec until the exec reports finished, so a non-zero tar/cred
exit isn't missed by reading exit_code too early. The backup only fails
on a definitively non-zero code (falls back to the empty-output check
if undeterminable).
- L-b: fixed two comments that referenced the old
write_bedrock_static_credentials name (now sync_bedrock_credentials).
- L-c: entrypoint only rewrites ~/.claude.json when awsAuthRefresh is
actually present, avoiding a needless jq reformat on every non-SSO
start.
- L-d: backup script traps EXIT to remove its mktemp staging dir even
when tar fails, so failed backups don't accumulate temp dirs (with the
sanitized config copy) in the container.
L-e (drop routing) is a non-issue: the layout is tabbed, so only one
terminal pane is ever visible; the active-guard routing is correct.
Verified the race fix, trap cleanup, grep guard, and exit-code polling.
cargo check / tsc / vitest all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- L4: sync_bedrock_credentials (renamed from write_bedrock_static_
credentials) now also clears a stale ~/.aws/credentials when the
project no longer uses static-credential Bedrock, so static keys don't
linger unused in the persistent home volume after switching backends.
Skipped when /tmp/.host-aws is mounted (host-managed ~/.aws). HOME is
also set explicitly on the exec env for robustness.
- M1: the Backup button now has a tooltip and the success toast notes
that the archive includes MCP/config which may contain MCP-embedded
API keys (OAuth tokens are excluded) — keep it private.
- L2: backup now uses async file IO (tokio::fs::File + AsyncWriteExt,
tokio::fs::remove_file) instead of blocking std::fs between awaits;
dropped-file reads use tokio::fs::metadata/read.
- L5: upload_host_file_to_terminal explicitly `mkdir -p`s
/tmp/triple-c-drops instead of relying on Docker's tar extractor to
create the parent dir.
Verified L4 cleanup guard, L5 mkdir, async IO, and exit-code paths
against real containers. cargo check / tsc / vitest all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes from the code review of this branch:
- Backup requires a running container (it runs via `docker exec`, which
can't run on a stopped one). Removed the misleading "Backup" button
from the stopped-project actions, added an explicit running check with
a clear error, and corrected the doc comment. (H1)
- jq sanitization fallback no longer leaks secrets: if ~/.claude.json
can't be parsed, the backup substitutes an empty object and warns to
stderr instead of copying the raw file (which held primaryApiKey /
oauthAccount). Verified the raw key never reaches the archive. (H2)
- Dropped-file paths typed into the terminal are now always single-quoted
(with '\'' escaping), not only when they contain whitespace — a name
like `foo$(whoami).txt` was previously sent raw into the shell. (M2)
- write_bedrock_static_credentials checks the exec exit code via the new
exec_oneshot_env_status and fails loudly on a write/chmod error instead
of silently reporting success. exec_oneshot keeps its
ignore-exit-code behavior so list_container_files is unaffected. (M4)
- Backup removes a partial/truncated archive on any stream error and
treats a non-zero tar exit code as failure (a truncated gzip was
previously reported as success). (L1)
- Dropped files are capped at 256 MiB to avoid ballooning host RAM
(the file is read fully into memory then re-tarred). (M3)
- Stopped excluding .git/objects from the backup so git history,
including unpushed commits, is preserved faithfully. (L3)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop files onto a terminal pane and they're copied into the container and
their in-container paths typed into the prompt, so Claude Code can read
them for reference — mirroring the existing image-paste flow.
Backend: upload_host_file_to_terminal reads the dropped host file and
writes it under /tmp/triple-c-drops/<name> in the session's container,
returning that path. Rejects directories and unreadable paths.
Frontend: TerminalView subscribes to Tauri's webview onDragDropEvent
(OS file drops are intercepted at the webview level, so HTML5 ondrop
wouldn't expose paths). The window-wide event is guarded by the pane's
`active` flag plus a bounds hit-test so a drop only affects the terminal
it landed on; multiple files are uploaded and their paths inserted
space-separated (quoted when they contain spaces).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extends download_container_backup to also capture the container's home
config so MCP servers, settings, and skills set up directly via Claude
Code (stored in ~/.claude.json / ~/.claude, on the home/config volumes
that a Reset wipes) survive a backup/restore cycle.
Secrets are stripped per the "exclude secrets" choice: ~/.claude.json is
filtered through jq to drop primaryApiKey/oauthAccount/customApiKeyResponses
(mcpServers and settings are kept), and ~/.claude/.credentials.json (the
OAuth tokens) is omitted. Staged config is archived under home-claude/ in
the tarball. Verified on the Ubuntu/jq container base.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a manual backup button on each project card (next to Start/Reset
when stopped, and next to Files when running) that saves a gzipped
tarball of the container's /workspace to a host path via the native save
dialog.
Backend: download_container_backup runs `tar czf -` inside the container
(so excludes + compression happen there rather than streaming a 16 GB
workspace) and pipes stdout straight to the chosen file. Regenerable
build artifacts (node_modules, target, .git/objects) are excluded so the
archive stays restore-sized. Returns bytes written; stderr is captured
for error reporting and a zero-byte result is treated as failure.
Works whether the container is running or stopped (only requires that it
exists). Verified on the Ubuntu/GNU-tar container base.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When a project switched backends (e.g. Bedrock -> Anthropic), the
recreated container kept authenticating against Bedrock, and SSO kept
firing after switching away. Three root causes, all fixed:
1. Recreation builds the new container from a `docker commit` snapshot.
commit always bakes the previous container's full ENV into the image
(an empty commit Config does NOT strip it, and the commit API cannot
remove env). So CLAUDE_CODE_USE_BEDROCK=1 / AWS_* survived into the
new container. Fix: create_container now explicitly clears every
managed auth key the active backend does not set (MANAGED_AUTH_KEYS),
so create-time env overrides the stale baked-in values.
2. awsAuthRefresh was written into ~/.claude.json (persisted home
volume) and never removed, so Claude Code kept invoking
triple-c-sso-refresh after switching to a non-SSO backend. Fix:
entrypoint now deletes awsAuthRefresh when AWS_SSO_AUTH_REFRESH_CMD
is unset, idempotent both ways.
3. Static/session AWS creds were baked into Config.Env at create time,
so a stop/start kept stale creds and rotated keys never refreshed
without a full recreation. Fix: static creds are no longer injected
as env vars; write_bedrock_static_credentials() writes
~/.aws/credentials (0600, secrets via exec env not argv) on every
start, and removes a stale ~/.aws/config left from a prior profile/SSO
session. Static creds also dropped from the bedrock fingerprint so a
key rotation refreshes in place instead of forcing recreation.
Adds exec_oneshot_env() for env-carrying one-shot execs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to PR review on terminal-layout-statusbar:
- [Major] Pin STT transcripts to the originating terminal. The single
useSTT instance is bound to the live active session, which can change
mid-recording. Capture the session id at recording start in a ref and
inject the transcript there instead of the live sessionId, so text
always lands in the terminal where recording began.
- [Minor] Clear the status-bar scroll state when the active terminal
unmounts, and null out termRef on dispose, so scrollActiveToBottom
can't point at a disposed terminal. Tab switches don't unmount, so
this only fires when the active session is actually closed.
- [Nit] Fix the terminal padding comment to match the symmetric value.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Terminal layout fixes for the xterm pane:
- Stop the terminal grid from clipping its rightmost column / bottom
row. The padding was on the element xterm mounts into, which the
FitAddon measures; the grid overhang got clipped. Padding now lives on
a wrapper and the xterm host fills it with no padding.
- Move the STT mic from a floating bottom-left overlay into the status
bar (far right). A single useSTT instance bound to the active session
now lives in App; Ctrl+Shift+M routes through the store.
- Move "Jump to Current" from a floating terminal overlay into the
status bar. The active TerminalView surfaces its scroll state and
scroll action via the store.
- Tighten terminal padding (was 8/12/48/16) now that nothing floats over
it, so the terminal claims as much area as possible.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The cmd-batch upload step POSTed to /releases unconditionally. On a
re-run the v{VERSION}-win tag already exists, so Gitea returns 409, the
findstr id parse yields an empty RELEASE_ID, and uploads go to a
malformed .../releases//assets URL -- all silently swallowed by cmd and
`curl -s`, so the step reported success while attaching no assets.
Rewrite in PowerShell mirroring the macOS job: look the release up by
tag first and create only on 404, throw if the id can't be resolved,
delete same-named assets left over from partial runs before re-upload,
and fail loudly (ErrorActionPreference=Stop, curl.exe -fsS with retries,
$LASTEXITCODE check).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a time-bounded `claude update` to entrypoint.sh that runs as the
claude user before the container is marked ready, so every terminal
session launches the latest CLI. Non-fatal and capped at 120s so an
offline/slow network never blocks container readiness; PATH covers both
~/.claude/bin and ~/.local/bin install locations.
Add flex-shrink-0 to the FileManagerModal header/footer so a long file
list can't squeeze them and the scroll region stays robust.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Right-click a tab (or double-click) to rename. Renamed labels show
as "ProjectName: CustomName" and are stored in the project's
renamed_session_names map. The entry is cleared on tab close.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New fields: GlobalAwsSettings.default_model_id, plus
GlobalOllamaSettings and GlobalOpenAiCompatibleSettings (base_url +
default_model_id each). When a per-project base_url or model_id is
blank, the container env vars and config fingerprints fall back to
the global value. Container recreation is triggered whenever the
resolved value changes, so editing a global default updates existing
projects on next start.
UI: added the new fields to AwsSettings and two new global settings
components, slotted into the Backends accordion.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Multiple-open accordion with per-section state persisted to
localStorage. Sections: General, Backends, Container, Git/SSH,
Tools, Updates. General is open by default; the rest are collapsed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Persist collapsed state in localStorage. When collapsed, render a
narrow rail with Projects/MCP/Settings icon buttons that expand the
sidebar to that view on click.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pulls in 15 upstream commits since the April 3 bundling snapshot
(msieurthenardier/mission-control). Notable changes:
- agentic-workflow rewritten as the "fast" variant: per-leg design and
implement, single review and commit across the whole flight
- New Skill-Project Boundary section: skills no longer read or write
project-owned artifacts by literal heading
- routine-maintenance scoped to post-mission only; adds state-machine
reachability and cache freshness audits
- Test metrics capture threaded through debrief, maintenance, and flight
- Crew prompts no longer carry skill-required instructions; SKILL.md is
the protocol
- Worktree git strategy removed; standardized on {target-project}
- Jira artifact template removed upstream
Local URL correction in init-project/README.md preserved
(anthropics/flight-control -> msieurthenardier/mission-control).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous fix only addressed the network flake; a re-run after any
upload failure still tripped over the leftover release record. The
naive POST /releases got 409 from Gitea, the grep-pipe parser yielded
an empty RELEASE_ID, and pipefail aborted with an opaque exit 1.
Now:
- Look up the release by tag first; reuse on 200, create on 404, fail
loudly on anything else.
- Validate RELEASE_ID is non-empty and surface the response body if
parsing fails.
- Before uploading each asset, check whether the release already has
an asset with that name (from a partial prior run) and DELETE it so
the POST is replace-not-conflict.
- Set -euo pipefail explicitly so the script's failure modes are
predictable rather than dependent on the runner's default flags.
Network hardening from the previous commit (HTTP/1.1, retries, -f) is
preserved. Linux and Windows blocks unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
macOS upload has been intermittently failing with curl exit 92
("HTTP/2 stream not closed cleanly") for several releases (v0.3.12,
v0.3.10, v0.3.1 all landed with empty asset arrays despite the per-tag
release record being created). It is not a size issue — Linux uploads
the 81MB AppImage on the same Gitea instance without trouble while the
Mac dmg is only 13.6MB.
Adds `--http1.1` to sidestep HTTP/2 stream multiplexing flakes on the
macOS runner, `-f` so HTTP errors no longer fail silently under `-s`,
and `--retry 5 --retry-all-errors --retry-delay 5 --max-time 600` to
absorb transient drops. Linux and Windows blocks unchanged; an inline
note in the YAML calls out where to mirror this if those start
failing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mac/Windows release builds failed the Tauri version-mismatch check:
tauri (2.11.0) vs @tauri-apps/api (2.10.1). The Linux fix only updated
the Rust lockfile; the npm lockfile was still at 2.10.x. Both lockfiles
now resolve to 2.11.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI's pre-build version check failed: tauri (2.10.2) vs @tauri-apps/api
(2.11.0). Both the Cargo.toml and package.json caret-pin to 2, so this is
purely a lockfile resolution fix — `cargo update -p tauri --precise
2.11.0` brings the Rust side up to match. Schema regeneration is included
since the gen/schemas/ output is keyed to the Tauri version.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sandbox mode: new per-project toggle that turns on Claude Code's bash
sandbox inside the container. Adds `bubblewrap` and `socat` to the
Dockerfile (the two Linux deps required by the sandbox), and emits a
managed `sandbox` block into `~/.claude/settings.json` via the existing
CLAUDE_CODE_SETTINGS_JSON entrypoint merge:
- `enabled` mirrors the Triple-C toggle and is always emitted, so the
entrypoint's recursive jq merge clears any prior on-state from the
persisted named volume — Triple-C is authoritative.
- `enableWeakerNestedSandbox: true` because we run inside Docker without
privileged user namespaces.
- `allowUnsandboxedCommands: false` to disable the `dangerouslyDisableSandbox`
escape hatch — opting into the sandbox shouldn't come with a runtime
bypass.
When sandbox is on, a SANDBOX_INSTRUCTIONS section is appended to
CLAUDE_INSTRUCTIONS so Claude can guide users through allowing extra
paths/domains, excluding `docker *`/`watchman *` from the sandbox, and
the rule that `sandbox.enabled` is owned by Triple-C. The Claude-Code
settings fingerprint includes sandbox state (only when on, to avoid
spuriously flagging existing containers for recreation on upgrade).
Bedrock service tier: new optional field on the per-project Bedrock
config. When set, exported as ANTHROPIC_BEDROCK_SERVICE_TIER (added in
Claude Code 2.1.122) and included in the Bedrock fingerprint.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Picks up the deprecation notes on dialog `ask`/`confirm` permissions
(now aliased to `allow-message`/`deny-message` and slated for removal
in Tauri v3). No behavior change — generated artifacts only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Trigger is workflow_dispatch exclusively so builds happen only when
explicitly requested from the Actions UI, not on every branch push.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors build-app.yml's three-platform matrix (Linux/macOS/Windows)
but uploads the bundles as workflow artifacts instead of creating
Gitea releases or syncing to GitHub, so feature branches can be
smoke-tested without cluttering the release streams.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When Docker isn't detected on startup, surface a dialog offering a
one-click install (pkexec + get.docker.com on Linux, brew cask on
macOS, winget on Windows) with a graceful fallback to manual steps
and a link to official documentation. Install output streams back
to the UI via a tauri event.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>