- Go 100%
Deepsoil #
This repo is pure vibeware. It works well enough, but I frankly don't know (or care) how it works.
Claude, with roots. A local, WTFPL-licensed wrapper that keeps Claude Code's terminal, tools and sessions while routing inference to an Anthropic Messages-compatible provider. DeepSeek's official API works as the default profile; custom HTTPS gateways and local servers are configurable. Go standard library only, with full source available.
deepsoil # ordinary interactive Claude, DeepSeek inference
deepsoil rc # native Remote Control server
deepsoil --remote-control # interactive session with Remote Control requested
deepsoil --remote-control --resume --model flash
deepsoil --bg "Work on this project"
deepsoil agents
deepsoil attach <id>
deepsoil -p "Explain this project" --tools Read
deepsoil --ds-provider local --model my-local-model
deepsoil --ds-provider anthropic # native Claude with its existing configuration
Claude owns its flags. Deepsoil intercepts only --ds-*; no separator is required. A literal -- retains its normal meaning: everything after it is passed literally, including strings that look like Deepsoil flags.
Verified: installed Claude Code 2.1.236 returned mocked streaming replies through the proxy with both the DeepSeek profile and a generic local model ID. A native background worker also displayed its mocked reply after the launcher exited, using a different proxy and CA from its already-running supervisor. Tests cover argument preservation, model roles, settings merging, credentials, streaming, persistent service restart and exit status. Manual validation: the project author reports a working live DeepSeek session and a fresh phone-created Remote Control session after the 0.3.2 proxy fix. Automated integration tests still use mocked providers; compatibility across accounts, client versions, and other providers is not established.
Start #
With Go 1.24 or newer, install directly from Tangled:
go install tangled.org/hotsocket.fyi/deepsoil@latest
Go installs deepsoil into GOBIN, or $(go env GOPATH)/bin by default; add that directory to your PATH. To install into ~/.local/bin instead:
GOBIN="$HOME/.local/bin" go install tangled.org/hotsocket.fyi/deepsoil@latest
From a source checkout, go install . builds and installs the local version. Claude Code must also be installed and on your PATH.
If using an archive with a bundled executable, make it available to your current shell from the archive directory:
export PATH="$PWD/bin:$PATH"
deepsoil --ds-version
deepsoil rc --ds-dry-run
This changes only the current shell's PATH. Alternatively, invoke ./bin/deepsoil. Nothing is globally installed. Rebuild with Go 1.24 or newer:
go build -trimpath -o bin/deepsoil .
Sign into Claude normally with deepsoil auth login. For DeepSeek, save it once with deepsoil --ds-token "YOUR_TOKEN", set DEEPSEEK_API_KEY in your terminal, or use --ds-key-file /path/to/key with a private file (chmod 600). For example, zsh can prompt without putting the key in shell history:
read -rs 'DEEPSEEK_API_KEY?DeepSeek API key: '
export DEEPSEEK_API_KEY
print
deepsoil --remote-control --name "My project"
unset DEEPSEEK_API_KEY
rc and remote-control launch Claude's standalone Remote Control server. Use deepsoil --remote-control for an interactive session with Remote Control enabled, or deepsoil --remote-control="My project" to supply a label. --name remains Claude's session display name.
The wrapper does not sign you in, grant eligibility, override organization policy, or change tool permission prompts. Claude's own first-party authentication remains necessary for the proxied workflow. Remote Control remains a Claude account feature even when inference is local.
Background sessions and phone access #
deepsoil --bg "Work on this project" # return while Claude keeps working
deepsoil --remote-control --bg "Start a remote session" # also request Remote Control
deepsoil agents # native agent view and new dispatches
deepsoil agents --json # native session inventory
deepsoil attach <id>
deepsoil respawn <id>
deepsoil logs <id>
deepsoil stop <id>
Put the prompt before variadic flags such as --tools, for example deepsoil --bg "Explain this" --tools Read. In the inspected native client, putting it after --tools ... --bg can make that prompt get parsed as another tool value and start an empty session. Deepsoil preserves Claude's argument ordering.
For new sessions created from your phone, Claude's standalone server mode is the relevant path. In a trusted Git project:
deepsoil remote-control --spawn worktree --capacity 4
The server supports creating separate sessions on demand; worktree asks Claude to isolate them in Git worktrees. Use --spawn same-dir for a shared directory. This server process must remain running; starting the Deepsoil proxy service alone does not publish a phone-accessible server. Native Remote Control confirmations, login, workspace trust, and account eligibility still apply. The project author reports a successful fresh phone-created session with the DeepSeek profile on 0.3.2. --bg by itself does not promise phone access.
rc is Claude's alias for the native remote-control server command; Deepsoil preserves both spellings. The server cannot accept a normal --settings overlay. Deepsoil supplies routing through the inherited environment and rejects known conflicting settings instead of silently replacing them. Its --model selection is applied through that environment. Server-side organization policy may still reject the session. Use interactive deepsoil --remote-control when you need the usual settings overlay.
Proxy service #
All proxied launches now use a detached, automatically started local service. That includes foreground sessions, because /background can detach one later. Claude still owns its background workers; Deepsoil owns their inference transport. Native Claude mode does not start this service.
deepsoil --ds-service status
deepsoil --ds-service restart
deepsoil --ds-service stop
These control Deepsoil's proxy, while deepsoil daemon ... controls Claude's supervisor. Stopping the proxy leaves Claude's sessions intact, but their proxied requests fail until it returns.
State lives in $XDG_STATE_HOME/deepsoil, or ~/.local/state/deepsoil. It includes a stable loopback port, a private Unix control socket, a private CA signing key, route authentication passwords, certificate bundles and durable launch settings. Directories are 0700 and files are 0600. Nothing is added to a system trust store or OS startup service.
Routes freeze the provider/model configuration and effective credential identity used at launch. Idle or completed Claude workers may be recreated later, so routes and settings are retained even after the launching command exits. A service restart restores the same proxy address and CA. If another process occupies that port, Deepsoil refuses to take over or silently move it. The service log contains startup errors and, with --ds-verbose, route paths/status; no request bodies or credentials.
Provider keys stay in service memory. Route files store credential references, not copies of the keys. On restart, saved config tokens or private key files restore routes. Environment-only credentials need re-registration by a launch with the original provider, model and key, or saving that same key and restarting the service. Changed/missing credentials make the old route unavailable; Deepsoil does not silently switch its account or fall back to Anthropic.
There is no automatic OS boot or crash supervisor. The next proxied Deepsoil launch, attach, respawn, or --ds-service restart starts the service again. Already-running Claude workers cannot revive it themselves. Saved routing/settings remain in state until you remove them; stop affected sessions and the service before removing that state.
Save a token #
deepsoil --ds-token "YOUR_TOKEN" # save for the default provider and exit
deepsoil --remote-control # reuse the saved token
deepsoil --remote-control --ds-token "YOUR_NEW_TOKEN" # save, then launch Remote Control
deepsoil --ds-provider gateway --ds-token "GATEWAY_TOKEN"
The token is stored as providers.<name>.token in the default config file, or in the file named by --ds-config. Missing directories are created with mode 0700; the config is replaced atomically with mode 0600. Existing profiles and the default provider are preserved. The token is plaintext in that owner-only file. As with any credential flag, a literal argument can appear in shell history and the process argument list; a shell variable avoids putting the literal in history.
Used alone, --ds-token saves and exits without requiring Claude to be installed. With Claude arguments, it saves and launches. With --ds-dry-run, it reports the intended save and exits without changing anything. Native Claude mode and auth: "none" profiles do not accept saved provider tokens.
A saved token takes precedence over the profile's environment variable. Saving clears the profile's previous key_file; a subsequent explicit --ds-key-file still overrides the saved token for that invocation. --ds-token and --ds-key-file cannot be combined. Tokens are stripped from the child arguments and never printed by Deepsoil.
Flags #
| Deepsoil flag | Meaning |
|---|---|
--ds-provider NAME |
Select a configured provider; defaults to default_provider, then deepseek |
--ds-config FILE |
Use an explicit profiles JSON file |
--ds-dir DIRECTORY |
Launch Claude in that project directory |
--ds-claude FILE |
Choose the Claude executable; defaults to claude on PATH |
--ds-service ACTION |
Inspect, stop or restart the persistent proxy service |
--ds-token TOKEN |
Save a provider token; alone, save and exit |
--ds-key-file FILE |
Override the selected profile's key source for this invocation |
--ds-dry-run |
Show provider/model routing without starting Claude or making network requests (reads profiles, including saved tokens) |
--ds-verbose |
Log request paths, destination category and status to the private service log; never bodies, headers or queries |
--ds-help / --ds-version |
Deepsoil help/version |
Flags may be mixed with Claude's options; both --ds-provider local and --ds-provider=local work. Claude's --help, --version, --verbose, --model, --resume, -p, --tools, --name, and --settings keep their native namespace. Deepsoil composes the native --model and --settings values with the chosen provider.
Native management commands such as auth, doctor, mcp, plugin, update, project, and setup-token, plus standalone --help/--version, launch Claude directly without a proxy or provider key. The anthropic provider also launches Claude directly; it preserves Claude's existing authentication, environment and settings rather than asserting where an already-configured Claude installation sends traffic.
Provider profiles #
No config is needed for DeepSeek. The built-in profile uses https://api.deepseek.com/anthropic, DEEPSEEK_API_KEY, and deepseek-v4-pro[1m]. Its pro and flash aliases select deepseek-v4-pro and deepseek-flash. Unspecified model roles use the selected main model.
The default config is $XDG_CONFIG_HOME/deepsoil/config.json, or ~/.config/deepsoil/config.json when XDG_CONFIG_HOME is unset. Deepsoil reads this file; --ds-token creates or updates it. Try the included example explicitly:
deepsoil --ds-config config.example.json --ds-dry-run
deepsoil --remote-control --ds-config config.example.json --ds-provider local --model my-model
The local model and gateway entries are placeholders: use a server that actually supports Anthropic Messages, and replace the model IDs/URL. OpenAI Chat Completions-only endpoints need a separate adapter; Deepsoil does not translate between those protocols.
A small custom profile looks like:
{
"default_provider": "local",
"providers": {
"local": {
"base_url": "http://127.0.0.1:8080",
"auth": "none",
"model": "my-main-model",
"models": {
"haiku": "my-small-model",
"subagent": "my-coding-model"
}
}
}
}
base_urlis the prefix before/v1/messages. Usehttps://host/anthropicfor a server exposing/anthropic/v1/messages, orhttp://127.0.0.1:8080for/v1/messages. Do not append/v1or/messages. HTTPS is required except for loopback HTTP. URL credentials, queries and fragments are rejected.authisx-api-key(default),bearer, ornone. Supply the credential throughkey_env, a privatekey_file, or--ds-key-file. File paths in profiles are relative to the config file; the CLI key path is relative to your invoking shell. Thetokenfield holds a saved token; configs containing tokens must be owner-only (chmod 600).auth: "none"rejects credentials.modelis the default main model.modelsmaps aliases or roles to real provider IDs. Supported native roles arefable,opus,sonnet,haiku, andsubagent. Other aliases such asflashare resolved by Deepsoil at launch. Values are concrete model IDs, not alias chains.- Append
[1m]only for models supporting that context window. Deepsoil preserves it for Claude's configuration and strips it from the upstream model ID. It does not add a 1M context claim to custom models automatically. - A custom entry replaces the entire named profile, including authentication references. The included example overrides DeepSeek's background/subagent roles to Flash; the built-in profile leaves all roles on the main model.
anthropicis reserved for native Claude. Unknown fields and invalid profiles produce errors rather than being silently ignored.
--model accepts a configured alias, a native role, or an explicit provider ID for this session. --model opusplan remains Claude's plan-mode behavior and uses the profile's Opus/Sonnet roles. In-session /model is still parsed by Claude: use a supported native role or a full model ID declared in the profile. Arbitrary profile aliases are not installed as new Claude commands, and picker presentation depends on the client version.
Requests for known Claude family IDs map to the corresponding provider role. Requests for other unconfigured model IDs are rejected. Every routed model stays on the selected provider. A provider error never triggers a fallback to Anthropic inference.
Transport and settings #
The original claude-rc changes ANTHROPIC_BASE_URL to localhost, which the inspected Claude build rejects for Remote Control. Deepsoil keeps Claude's normal API base and uses a private authenticated HTTPS CONNECT proxy instead.
The service generates a private local CA on first use and persists it so existing workers trust it after restart. Its short-lived api.anthropic.com leaf certificates renew automatically. The public CA is supplied through each child's NODE_EXTRA_CA_CERTS; existing extra certificates are preserved per route. No system trust store is edited. Other HTTPS hosts use opaque tunnels. Clients such as the native Remote Control server may also send absolute-form HTTPS requests for api.anthropic.com; these use the same authenticated routing and preserve the HTTP method. The listener chooses a loopback port initially and retains it, with a different authentication password for each frozen route.
For Messages and count-token requests, Deepsoil rewrites the model, removes account metadata and replaces request headers with a small allowlist plus the selected provider's credential. The wrapper can see Anthropic OAuth headers in memory but does not forward them to the provider or log them. Prompt and tool content go to the configured provider. Other Anthropic routes retain their original authentication.
For normal/background launches and agent view, native --settings JSON or files are merged into a private durable session file. Permissions, hooks and unrelated options are preserved; routing/auth/model environment values and apiKeyHelper are owned by Deepsoil for the proxied session. Configured provider key variables are removed from the child environment and masked in session settings. Saved tokens stay in the owner-only Deepsoil config; provider credentials are never copied into launch settings. Claude's regular settings, history and session writes remain its own behavior.
Child exit closes the launcher while the service and its route settings remain available. SIGINT/SIGTERM are forwarded to the directly launched child, and its exit code propagates. The service's CA lasts five years; its seven-day leaf certificates renew as needed. Do not delete the CA/state while workers depend on them.
Limits #
- Proxied providers support foreground, print, resume, native background workers, agent view, attach/respawn, and Remote Control launch modes. Tmux wrapping, self-hosted-runner/gateway commands and cloud ultrareview remain unsupported. Ordinary in-session subagents use the configured model routing.
- Live DeepSeek and phone-created Remote Control have been manually reported working by the project author; broader compatibility is not established. Official docs do not certify this mixed-provider arrangement. It must still satisfy Claude's account and server-side checks.
- Providers must implement Anthropic Messages semantics, including whatever tools, streaming, thinking and content blocks your Claude session uses. Deepsoil does not emulate unsupported features. Token counting is forwarded; provider support varies. No token counts are fabricated.
- Known Messages routes are handled; batches and legacy completion routes are rejected. This does not cover every future inference endpoint or every plugin's independent network traffic.
- Existing alternate cloud-provider modes and upstream proxy settings are rejected for proxied sessions. Corporate proxy chaining and client-certificate authentication are not implemented. Native mode leaves those settings with Claude.
- Opt-outs and organization policy remain in effect. The wrapper never independently retrieves Keychain credentials, edits the global model cache, installs an OS startup service or kills unrelated processes.
- Client-side CONNECT supports HTTPS port 443; absolute-form proxy requests support the same port for
api.anthropic.com. The provider connection is separate and may use configured ports, including loopback HTTP. Node tools launched by Claude inherit its proxy/CA environment; other HTTPS stacks may not use those settings. - Tested on macOS ARM64. Linux has not been runtime-tested; Windows is unsupported by the Unix signal handling.
Validate and source #
go test -race ./...
go vet ./...
CLAUDE_INTEGRATION_BINARY="$(command -v claude)" go test -race -v ./...
Tests need loopback listeners. The opt-in real-Claude fixtures use disposable config, fake credentials, no enabled tools, and mocked upstream responses. The background fixture creates an isolated native supervisor, dispatches through a different proxy and CA, holds the mock response until the launcher exits, and verifies the worker displays it. It stops that supervisor and removes its test sessions afterward. Fixtures block unrelated proxy destinations and do not use your account or call live providers. validation.txt records the packaged build's test results.
cli.go owns the reserved flags and native dispatch; config.go owns profiles, model selection and credentials; main.go owns launch/settings/lifecycle; service.go owns the persistent route service; server.go checks conflicts for native Remote Control server mode; proxy.go owns routing and CONNECT; cert.go owns certificate generation and renewal. The *_test.go files exercise those boundaries. The teardown evidence remains in the separate claude-rc-re artifact; original decompiled code was not copied here.
Since 0.3.1, rc preserves Claude's native server meaning. Replace the former deepsoil rc interactive shortcut with deepsoil --remote-control. For the former 0.1 command-line options, replace wrapper --dir, --key-file, --dry-run, and --verbose with their --ds-* forms. --model remains native syntax. Ordinary deepsoil now starts a local interactive session without requesting Remote Control.
References: Claude background sessions, Claude CLI, model configuration, Remote Control, proxy/CA settings, and DeepSeek's Anthropic API. These describe the component features, not certification of this combined setup.