Skip to content
Merged
7 changes: 6 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Tests live in `tests/`.

- Use Python 3.12+.
- Keep changes scoped to the requested behavior.
- Follow the existing module boundaries: CLI orchestration in `cli.py`, CLI-agent behavior in `agents/<name>.py`, desktop-app adapters in `agents/desktop/`, shared agent dispatch in `agents/__init__.py`, Databricks calls in `databricks.py`, skill download (UC fetch client + on-disk writer + download orchestration) in `skills_download.py`, MCP-connection state glue in `mcp.py`, and presentation helpers in `ui.py`. Skill download persists no disk state — it writes files to `--path` (or the home dir) and registers only the schema-less skills MCP connection. `ug configure skills` with no `--location` (or `--mcp` with no `--location`) registers that schema-less connection without downloading anything.
- Follow the existing module boundaries: CLI orchestration in `cli.py`, CLI-agent behavior in `agents/<name>.py`, desktop-app adapters in `agents/desktop/` with CLI setup/cleanup orchestration in `agents/desktop/setup.py`, shared agent dispatch in `agents/__init__.py`, Databricks calls in `databricks.py`, skill download (UC fetch client + on-disk writer + download orchestration) in `skills_download.py`, MCP-connection state glue in `mcp.py`, and presentation helpers in `ui.py`. Skill download persists no disk state — it writes files to `--path` (or the home dir) and registers only the schema-less skills MCP connection. `ug configure skills` with no `--location` (or `--mcp` with no `--location`) registers that schema-less connection without downloading anything.
- Prefer existing helpers for config file writes, state persistence, UI messages, and Databricks authentication.
- Use `ucode.os_compatibility.subprocess_cross_os.run` / `ucode.os_compatibility.subprocess_cross_os.popen` for subprocesses; they resolve Windows npm wrappers automatically and default text streams to UTF-8 with replacement for invalid bytes. Keep commands as argument lists. Do not repeat these encoding defaults at callsites; explicit encoding/error overrides and binary mode remain supported. Ruff rejects direct `subprocess.run` / `subprocess.Popen` calls outside `os_compatibility/subprocess_cross_os.py` and tests.
- Use `acquire_exclusive_file_lock` / `release_file_lock` from `ucode.os_compatibility.file_lock_cross_os` instead of calling `fcntl.flock`, `fcntl.lockf`, or `msvcrt.locking` directly. Ruff enforces this outside the compatibility module and tests.
Expand Down Expand Up @@ -154,6 +154,11 @@ When `claude_otel_tracing` is enabled, Desktop's reserved profile also owns
for the existing `otel-headers` command. Native sessions rerun it as tokens rotate;
no bearer is persisted. Disable/revert removes the wrapper, with atomic writes and
rollback shared with the profile. Disabled tracing omits these fields on replacement.
Managed Claude setup also installs a generated Cowork plugin containing only the current
workspace's managed skills and Claude-targeted MCP servers. The source lives at
`~/.ucode/claude-cowork-marketplace`, and `~/.ucode/claude-cowork.json` records the selected
account/org root for cleanup. Cowork must have started once. Setup and cleanup use scoped
`claude plugin ... --cowork --json` commands with `CLAUDE_CONFIG_DIR`; failures stay best-effort.
See `docs/claude-desktop.md` for native validation limits and revert behavior.

<details>
Expand Down
86 changes: 71 additions & 15 deletions docs/claude-desktop.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,60 @@ Windows, and Linux. This uses
the same workspace, Databricks CLI OAuth profile, model source, and managed HTTP
headers as Claude Code. There is no separate Desktop checkbox or managed field.

## Requirements and setup

- Claude Desktop installed on macOS, Windows, or Linux. On Windows/Linux, open it
once to initialize application data.
- A named Databricks CLI OAuth profile with gateway/model access. A bearer token
alone is not enough for Desktop's credential helper.
- At least one Claude-named model in the configured static list or gateway catalog.

Quit Claude Desktop, configure Claude Code, then reopen Desktop normally:

```bash
ug configure --profile <your-profile> --agents claude
```

Quit Claude Desktop before configuring, then reopen it normally from your app launcher.
No terminal process needs to stay running. Claude Desktop must already be installed;
UG does not install it or manage the customer's MDM process. On Windows and Linux,
open Desktop once before configuring so it initializes its application-data directory.
No terminal process needs to stay running. UG does not install Desktop or manage
the customer's MDM process. Explicit-agent, selected-agent, and managed configure
flows all set up Desktop after successful Claude Code configuration. Ordinary agent
launches and `ug agents add` do not configure Desktop.

## Cowork workspace skills and MCP servers

Whenever Claude is configured, `ug configure` also installs a generated
`unity-gateway@unity-gateway-cowork` plugin into that account's Cowork scope. This applies
to managed and unmanaged workspaces. Start one Cowork session before configuring so Desktop
creates its active account/organization directory. If several Cowork profiles exist and UG
cannot identify one active profile, setup warns without changing any of them.

The plugin contains the current workspace's Claude-targeted MCP servers. In a managed
workspace, that includes both user-selected and managed MCP servers, plus managed skills.
In an unmanaged workspace, it includes user-selected MCP servers. User, project, unmanaged
Databricks AI Tools, and other-workspace skills are not copied. `ug configure --mcp`,
`ug mcp add`, and `ug mcp remove` resync the plugin. MCP entries run the absolute
`ug mcp-proxy` executable with the selected workspace and CLI profile; no bearer token is
stored in the plugin. Saved PAT mode is supported. Custom OAuth is not yet supported for
Cowork MCP servers.

UG owns these local files:

- Generated marketplace: `~/.ucode/claude-cowork-marketplace`
- Selected Cowork root record: `~/.ucode/claude-cowork.json`

Start a new Cowork session after configure. Plugin MCP servers connect asynchronously and
may take a few seconds to appear, so a tool can be absent on the first model turn. Deferred
tool search or a retry after another tool call should find it. The resulting tool name follows
Claude's `mcp__plugin_<plugin>_<server>__<tool>` pattern.

Cowork plugin support can still be disabled by Anthropic account feature flags or managed
Desktop policy. UG treats installation as best-effort: failure warns but does not fail Claude
Code setup. If the current workspace has no Claude-targeted MCP servers or managed skills, UG
keeps the plugin installed but replaces its contents with an empty plugin so a prior workspace's
tools and skills do not remain active. If Cowork has never been started and UG has no prior plugin
state, setup skips silently. Only `ug revert` removes the plugin registration and generated
marketplace. The native Desktop gateway profile is separate and remains under the cleanup rules
below.

## Models and authentication

Expand Down Expand Up @@ -133,23 +179,32 @@ otherwise it clears the selection. A later selection of another profile is prese
Only this previous-selection ID is saved in `~/.ucode/claude-desktop.json`.
Repeated configure retains it while UG remains selected.

Revert also uninstalls `unity-gateway@unity-gateway-cowork`, removes its marketplace
registration, and deletes UG's generated marketplace. This removes the MCP connectors and
skills delivered by that plugin. It also cleans up an exact UG registration left in another
Cowork profile by an older failed revert. Unrelated Desktop plugins, connectors, and skills are
left untouched.

The revert summary reports `Claude Desktop profile: removed`, `unchanged`, or `failed`.

Old random-ID and workspace-derived profiles from earlier builds are left untouched;
there is no automatic migration or cleanup. Workspace-specific UUID normalization
is no longer needed; normal CLI URL handling is unchanged.

Files are replaced atomically one at a time with best-effort rollback of their exact
previous bytes on write failure. This is not a crash-atomic transaction across files.
Workspace state is cleared even if Desktop revert fails. Desktop's separate
previous-selection file is retained on failure, so cleanup can still be retried
with `ug revert`.
Workspace and Cowork cleanup state is retained if Desktop revert fails, so cleanup can be
retried with `ug revert`. The generated Cowork marketplace is also retained until its plugin
and marketplace registrations are removed successfully. A Desktop cleanup failure produces
one warning and exit code 1; the summary reports the failed cleanup.
Profile configure/revert waits at most five seconds for its file lock. A timeout
does not interrupt the holder or change profile, metadata, or selection-state files.

Desktop failures are warnings: successful Claude Code setup still returns exit 0.
`--dry-run` performs no Desktop discovery or writes. Removing Claude from managed
configuration does not revoke a previously written Desktop profile. Desktop does
not run UG's launch-time managed-agent checks; gateway authorization remains the
enforcement boundary.
Desktop setup failures only warn: successful Claude Code configuration still returns exit 0.
`--dry-run` performs no Desktop or Cowork discovery, writes, or plugin commands. Removing Claude
from managed configuration preserves both the Cowork plugin and a previously written native
Desktop profile until `ug revert`. Desktop does not run UG's launch-time managed-agent checks;
gateway authorization remains the enforcement boundary.

## Validation limits

Expand All @@ -174,9 +229,10 @@ orchestration; they do not prove GUI inference on every app version.
models without renaming them; that name filter does not reproduce every native
validation rule.
- Anthropic subscription relay, custom OAuth/PAT profiles, Desktop Smart Routing,
and connector/plugin compatibility are not implemented here. Native OTEL settings
are generated, but native export and ingestion remain unverified; session auth
limits are described above.
and third-party connectors outside UG's generated Cowork plugin are not implemented here.
Cowork's MCP proxy supports saved PAT mode but not custom OAuth. Native OTEL settings are
generated, but native export and ingestion remain unverified; session auth limits are
described above.
- Observed inference applies to Cowork. Ordinary Chat is not claimed to use the
same gateway path.

Expand Down
Loading
Loading