@useshifu/coding-harness 0.3.22 → 0.3.23
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.
- package/README.md +11 -7
- package/bin/shifu-harness.js +62 -24
- package/package.json +1 -1
- package/skills/shifu-context/SKILL.md +2 -2
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ To disconnect this device, run `npx --yes @useshifu/coding-harness disconnect --
|
|
|
32
32
|
|
|
33
33
|
## Operate
|
|
34
34
|
|
|
35
|
-
Version `0.3.
|
|
35
|
+
Version `0.3.23` is the npm `latest` release. It retrieves context at substantive task starts and new topics, tracks current topic coverage, and surfaces Shifu-attributed support or discrepancies alongside proposals and actions. Current user instructions take precedence over historical context; adopted choices and rationale remain available to existing session sync.
|
|
36
36
|
|
|
37
37
|
Version `0.3.21` adds meaningful decision and reflection checkpoints to the managed context guidance: historical reinforcement, discrepancies and goal-aware coaching, with current-context reuse and optional clarification. Existing managed blocks refresh on upgrade.
|
|
38
38
|
|
|
@@ -91,7 +91,7 @@ The AI Profile page shows detected categories, model and thinking labels, and Je
|
|
|
91
91
|
|
|
92
92
|
The connection endpoint returns `recommendedPackageVersion`, pinned to a published release. Before `sync`, `sync-files`, `approve`, or `scheduled-sync`, the runner compares its embedded release version with that property. An older runner installs the exact recommended release through npm and resumes the original command with the updated runner. Equal or newer runners continue unchanged. Explicitly recommended major releases follow the same comparison rule. Missing or invalid recommendations, connection failures, and npm failures do not block sync. The connection, pending work, checkpoints, and schedule are preserved.
|
|
93
93
|
|
|
94
|
-
This update mechanism first ships in `0.3.10`. Runners from earlier releases need a one-time installation of a release containing it (`npx --yes @useshifu/coding-harness@0.3.
|
|
94
|
+
This update mechanism first ships in `0.3.10`. Runners from earlier releases need a one-time installation of a release containing it (`npx --yes @useshifu/coding-harness@0.3.23 install --harness codex`). Raise the server recommendation only after the target release is published and its backend requirements are deployed.
|
|
95
95
|
|
|
96
96
|
## Force sync local work
|
|
97
97
|
|
|
@@ -122,7 +122,7 @@ Setup preserves other instruction text and MCP settings. Package installation re
|
|
|
122
122
|
The context branch adds a remote MCP connection using the same saved Codex key:
|
|
123
123
|
|
|
124
124
|
```sh
|
|
125
|
-
npx --yes @useshifu/coding-harness@0.3.
|
|
125
|
+
npx --yes @useshifu/coding-harness@0.3.23 mcp-setup --harness codex --mcp-url https://YOUR-BRANCH-HOST/mcp
|
|
126
126
|
```
|
|
127
127
|
|
|
128
128
|
For development, install dependencies and run from the checkout root:
|
|
@@ -153,23 +153,27 @@ Official configuration reference: https://learn.chatgpt.com/docs/config-file/con
|
|
|
153
153
|
OpenCode uses the same `/mcp` endpoint and three tools, authenticated with its own saved OpenCode connection key:
|
|
154
154
|
|
|
155
155
|
```sh
|
|
156
|
-
npx --yes @useshifu/coding-harness@0.3.
|
|
156
|
+
npx --yes @useshifu/coding-harness@0.3.23 mcp-setup --harness opencode --mcp-url https://YOUR-SHIFU-HOST/mcp
|
|
157
157
|
```
|
|
158
158
|
|
|
159
159
|
For checkout usage, install dependencies with `npm ci --prefix packages/shifu-coding-harness --ignore-scripts` from the checkout root, then run the checkout CLI with the same arguments. Setup preserves existing sync settings and other MCP servers, checks authenticated initialization and tool discovery, and installs the `shifu-context` usage instructions. A missing OpenCode connection prompts for its key in the terminal. A Codex key cannot authorize an OpenCode connection.
|
|
160
160
|
|
|
161
|
-
The installer
|
|
161
|
+
The installer detects OpenCode 1.x or 2.x and validates configuration through that installed client before changing files. V1 uses `mcp.shifu`; V2 uses `mcp.servers.shifu`, direct tool exposure (`codemode: false`), and separate startup/catalog (30 seconds) and execution (300 seconds) budgets. Older V2 builds that discard these options fail validation with an update instruction. Existing unrelated settings and comments are preserved. A managed V1 Shifu entry in the selected file moves to the V2 location during setup.
|
|
162
|
+
|
|
163
|
+
The installer adds a remote `shifu` entry with `oauth: false` to OpenCode's JSON or JSONC configuration, preserving existing content and comments. Its Authorization header uses OpenCode's `{file:...}` substitution to read a protected local credential file; the key stays out of configuration, command arguments and chat. Replacing the saved connection key refreshes that file; disconnect removes it. Restart OpenCode and start a new session after setup. For V2, run `opencode service stop` before reopening it so the background service loads the new connection. Project-specific configuration can override global MCP settings; inspect `opencode mcp list` in the project if tools do not appear.
|
|
162
164
|
|
|
163
165
|
The API derives the harness and tenant from the authenticated connector key. Memory updates from OpenCode carry `opencode` provenance; personal eligibility, general retrieval and evidence verification use the same rules as Codex. Coding-session sync remains separate. No additional local MCP server or OpenCode plugin is required.
|
|
164
166
|
|
|
165
|
-
Official references: [MCP servers](https://docs
|
|
167
|
+
Official references: [V1 MCP servers](https://opencode.ai/docs/mcp-servers/), [V2 MCP servers](https://opencode.ai/v2/docs/mcp-servers/) and [V2 migration](https://opencode.ai/v2/docs/migrate-v1/).
|
|
168
|
+
|
|
169
|
+
For the optional native integration gate, set `SHIFU_TEST_OPENCODE_BIN` to a temporary official OpenCode 2.x binary and run `node --test test/opencode-native.test.js` from this package. It uses isolated configuration, a synthetic credential and local MCP/model fixtures; it checks setup, native credential-file authentication, discovery and a model-driven tool call without a user key or paid model.
|
|
166
170
|
|
|
167
171
|
## Claude Code context and memory
|
|
168
172
|
|
|
169
173
|
Claude Code connects to the same `/mcp` endpoint and three tools with its own saved connection key:
|
|
170
174
|
|
|
171
175
|
```sh
|
|
172
|
-
npx --yes @useshifu/coding-harness@0.3.
|
|
176
|
+
npx --yes @useshifu/coding-harness@0.3.23 mcp-setup --harness claude_code --mcp-url https://YOUR-SHIFU-HOST/mcp
|
|
173
177
|
```
|
|
174
178
|
|
|
175
179
|
For checkout usage, install dependencies as above and run the checkout CLI with these arguments. Setup checks the existing Claude Code key, authenticated initialization and tool discovery, and installs the `shifu-context` skill. It preserves the sync endpoint, schedule, checkpoints and other MCP servers. A missing connection prompts for a Claude Code key in the terminal; do not substitute a Codex or OpenCode key.
|
package/bin/shifu-harness.js
CHANGED
|
@@ -40,7 +40,7 @@ const MAX_TURNS_PER_SEGMENT = 12;
|
|
|
40
40
|
const MAX_TITLE_LENGTH = 160;
|
|
41
41
|
const MAX_WORK_DETAIL_LENGTH = 600;
|
|
42
42
|
const CONFIG_VERSION = 2;
|
|
43
|
-
const RUNNER_VERSION = "0.3.
|
|
43
|
+
const RUNNER_VERSION = "0.3.23";
|
|
44
44
|
const REDACTION_VERSION = 4;
|
|
45
45
|
const DEFAULT_INTERVAL_HOURS = 1;
|
|
46
46
|
const LEGACY_INTERVAL_HOURS = 4;
|
|
@@ -1430,7 +1430,7 @@ async function validateConnection(apiUrl, token, harness) {
|
|
|
1430
1430
|
|
|
1431
1431
|
async function connect(harness, readKey = readSecret) {
|
|
1432
1432
|
const existing = readJSON(configPath(harness), undefined);
|
|
1433
|
-
const refreshContextKey = harness === "opencode" && existing?.mcpUrl && openCodeMcpConfigs().some((config) => managedOpenCodeMcp(config.value?.mcp?.shifu));
|
|
1433
|
+
const refreshContextKey = harness === "opencode" && existing?.mcpUrl && openCodeMcpConfigs(existing.mcpConfigMajor).some((config) => managedOpenCodeMcp(config.value?.mcp?.shifu) || managedOpenCodeMcp(config.value?.mcp?.servers?.shifu));
|
|
1434
1434
|
const token = (await readKey()).trim();
|
|
1435
1435
|
if (!TOKEN_PATTERN.test(token)) throw new Error("The connection key is invalid.");
|
|
1436
1436
|
const apiUrl = requireSafeApiUrl(option("--api-url") || existing?.apiUrl || process.env.SHIFU_API_URL || DEFAULT_API_URL);
|
|
@@ -1609,8 +1609,18 @@ function openCodeTokenPath() {
|
|
|
1609
1609
|
return file;
|
|
1610
1610
|
}
|
|
1611
1611
|
|
|
1612
|
-
function
|
|
1613
|
-
|
|
1612
|
+
function openCodeVersion() {
|
|
1613
|
+
try {
|
|
1614
|
+
const output = execFileSync(process.env.SHIFU_OPENCODE_BIN || "opencode", ["--version"], { stdio: ["ignore", "pipe", "pipe"], encoding: "utf8", timeout: 10_000, maxBuffer: 1024 * 1024 });
|
|
1615
|
+
const version = output.trim().match(/^(?:opencode\s+)?v?(\d+\.\d+\.\d+)(?:[-+][\w.-]+)?$/)?.[1];
|
|
1616
|
+
if (version && [1, 2].includes(Number(version.split(".")[0]))) return version;
|
|
1617
|
+
} catch { /* Native output can contain settings; report only the remedy. */ }
|
|
1618
|
+
throw new Error("Could not identify a supported OpenCode 1.x or 2.x client. Install or update OpenCode before MCP setup; nothing was changed.");
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
function openCodeMcpConfigs(major = 1) {
|
|
1622
|
+
const names = major === 2 ? ["opencode.json", "opencode.jsonc"] : ["config.json", "opencode.json", "opencode.jsonc"];
|
|
1623
|
+
return names.map((name) => {
|
|
1614
1624
|
const file = path.join(openCodeConfigRoot(), name);
|
|
1615
1625
|
const exists = fs.existsSync(file);
|
|
1616
1626
|
if (exists && !fs.lstatSync(file).isFile()) throw new Error("OpenCode configuration must be a regular file, not a link. Nothing was changed.");
|
|
@@ -1620,7 +1630,7 @@ function openCodeMcpConfigs() {
|
|
|
1620
1630
|
if (errors.length || !value || typeof value !== "object" || Array.isArray(value) || (value.mcp !== undefined && (!value.mcp || typeof value.mcp !== "object" || Array.isArray(value.mcp)))) {
|
|
1621
1631
|
throw new Error("OpenCode configuration is invalid. Fix its JSON/JSONC before MCP setup; nothing was changed.");
|
|
1622
1632
|
}
|
|
1623
|
-
if (value.$schema && value.$schema !== "https://opencode.ai/config.json") throw new Error("This OpenCode configuration schema is unsupported. Use the OpenCode
|
|
1633
|
+
if (value.$schema && value.$schema !== "https://opencode.ai/config.json") throw new Error("This OpenCode configuration schema is unsupported. Use the official OpenCode config.json schema before MCP setup.");
|
|
1624
1634
|
return { file, original, exists, value };
|
|
1625
1635
|
});
|
|
1626
1636
|
}
|
|
@@ -1629,8 +1639,9 @@ function managedOpenCodeMcp(config) {
|
|
|
1629
1639
|
return config?.type === "remote" && config.headers?.Authorization === `Bearer {file:${openCodeTokenPath()}}`;
|
|
1630
1640
|
}
|
|
1631
1641
|
|
|
1632
|
-
function editOpenCodeMcp(original, value) {
|
|
1633
|
-
|
|
1642
|
+
function editOpenCodeMcp(original, value, major = 1) {
|
|
1643
|
+
const target = major === 2 ? ["mcp", "servers", "shifu"] : ["mcp", "shifu"];
|
|
1644
|
+
return jsonc.applyEdits(original || "{}\n", jsonc.modify(original || "{}\n", target, value, { formattingOptions: { insertSpaces: true, tabSize: 2, eol: "\n" } }));
|
|
1634
1645
|
}
|
|
1635
1646
|
|
|
1636
1647
|
function writePrivateText(file, text) {
|
|
@@ -1648,12 +1659,15 @@ function unchangedConfig(config) {
|
|
|
1648
1659
|
return fs.existsSync(config.file) === config.exists && (config.exists ? fs.readFileSync(config.file, "utf8") : "") === config.original;
|
|
1649
1660
|
}
|
|
1650
1661
|
|
|
1651
|
-
function validateOpenCodeMcpConfig(configs, prepared, mcpUrl) {
|
|
1662
|
+
function validateOpenCodeMcpConfig(configs, prepared, mcpUrl, major) {
|
|
1652
1663
|
const temporary = fs.mkdtempSync(path.join(os.tmpdir(), "shifu-opencode-mcp-"));
|
|
1653
1664
|
const configDirectory = path.join(temporary, "config", "opencode");
|
|
1654
1665
|
const probeToken = path.join(temporary, "probe.key");
|
|
1655
1666
|
const environment = { ...process.env, HOME: temporary, XDG_CONFIG_HOME: path.join(temporary, "config"), XDG_DATA_HOME: path.join(temporary, "data"), XDG_CACHE_HOME: path.join(temporary, "cache"), XDG_STATE_HOME: path.join(temporary, "state"), OPENCODE_DISABLE_PROJECT_CONFIG: "1" };
|
|
1656
|
-
for (const key of
|
|
1667
|
+
for (const key of Object.keys(environment)) {
|
|
1668
|
+
if (major === 2 ? key.startsWith("OPENCODE_") : ["OPENCODE_CONFIG", "OPENCODE_CONFIG_DIR", "OPENCODE_CONFIG_CONTENT", "OPENCODE_PERMISSION"].includes(key)) delete environment[key];
|
|
1669
|
+
}
|
|
1670
|
+
environment.OPENCODE_DISABLE_PROJECT_CONFIG = "1";
|
|
1657
1671
|
try {
|
|
1658
1672
|
fs.mkdirSync(configDirectory, { recursive: true, mode: 0o700 });
|
|
1659
1673
|
fs.writeFileSync(probeToken, "shifu-probe-only", { mode: 0o600 });
|
|
@@ -1667,34 +1681,57 @@ function validateOpenCodeMcpConfig(configs, prepared, mcpUrl) {
|
|
|
1667
1681
|
});
|
|
1668
1682
|
fs.writeFileSync(path.join(configDirectory, path.basename(config.file)), text, { mode: 0o600 });
|
|
1669
1683
|
}
|
|
1670
|
-
const
|
|
1671
|
-
const
|
|
1672
|
-
|
|
1684
|
+
const command = process.env.SHIFU_OPENCODE_BIN || "opencode";
|
|
1685
|
+
const options = { cwd: temporary, env: environment, stdio: ["ignore", "pipe", "pipe"], encoding: "utf8", timeout: 30_000, maxBuffer: 8 * 1024 * 1024 };
|
|
1686
|
+
// V2 debug commands otherwise attach to a shared daemon, even with an isolated HOME.
|
|
1687
|
+
if (major === 2) execFileSync(command, ["service", "set", "disabled", "true"], options);
|
|
1688
|
+
const args = major === 2 ? ["debug", "config"] : ["debug", "config", "--pure"];
|
|
1689
|
+
const output = execFileSync(command, args, options);
|
|
1690
|
+
const report = JSON.parse(output);
|
|
1691
|
+
const resolved = major === 2
|
|
1692
|
+
? report.find((source) => source.type === "document" && source.path === path.join(configDirectory, path.basename(prepared.file)))?.info?.mcp?.servers?.shifu
|
|
1693
|
+
: report.mcp?.shifu;
|
|
1694
|
+
const accepted = major === 2
|
|
1695
|
+
? resolved?.disabled !== true && resolved?.codemode === false && resolved?.timeout?.startup === 30_000 && resolved?.timeout?.catalog === 30_000 && resolved?.timeout?.execution === 300_000 && resolved?.headers?.Authorization === "***"
|
|
1696
|
+
: resolved?.enabled === true && resolved?.timeout === 120_000 && resolved?.headers?.Authorization === "Bearer shifu-probe-only";
|
|
1697
|
+
if (resolved?.type !== "remote" || resolved.url !== mcpUrl || resolved.oauth !== false || !accepted) {
|
|
1673
1698
|
throw new Error("OpenCode did not accept the expected Shifu remote MCP configuration.");
|
|
1674
1699
|
}
|
|
1675
1700
|
} catch (error) {
|
|
1676
1701
|
if (error?.code === "ENOENT") throw new Error("The opencode command is unavailable. Install OpenCode CLI before MCP setup.");
|
|
1677
1702
|
// Native diagnostics may contain expanded secrets from existing settings.
|
|
1678
|
-
throw new Error(
|
|
1703
|
+
throw new Error(`OpenCode could not validate its ${major}.x remote MCP configuration. Update OpenCode or fix its existing config; nothing was changed.`);
|
|
1679
1704
|
} finally {
|
|
1680
1705
|
fs.rmSync(temporary, { recursive: true, force: true });
|
|
1681
1706
|
}
|
|
1682
1707
|
}
|
|
1683
1708
|
|
|
1684
1709
|
function prepareOpenCodeMcpConfig(mcpUrl) {
|
|
1685
|
-
const
|
|
1710
|
+
const major = Number(openCodeVersion().split(".")[0]);
|
|
1711
|
+
const configs = openCodeMcpConfigs(major);
|
|
1686
1712
|
const selected = configs.findLast((config) => config.exists) || configs.at(-1);
|
|
1687
|
-
const entry = {
|
|
1688
|
-
|
|
1689
|
-
|
|
1713
|
+
const entry = {
|
|
1714
|
+
type: "remote", url: mcpUrl, oauth: false,
|
|
1715
|
+
headers: { Authorization: `Bearer {file:${openCodeTokenPath()}}` },
|
|
1716
|
+
...(major === 2
|
|
1717
|
+
? { disabled: false, codemode: false, timeout: { startup: 30_000, catalog: 30_000, execution: 300_000 } }
|
|
1718
|
+
: { enabled: true, timeout: 120_000 }),
|
|
1719
|
+
};
|
|
1720
|
+
let candidate = selected.original;
|
|
1721
|
+
if (major === 2 && managedOpenCodeMcp(selected.value.mcp?.shifu)) candidate = editOpenCodeMcp(candidate, undefined);
|
|
1722
|
+
const prepared = { ...selected, candidate: editOpenCodeMcp(candidate, entry, major), configs, openCodeMajor: major };
|
|
1723
|
+
validateOpenCodeMcpConfig(configs, prepared, mcpUrl, major);
|
|
1690
1724
|
return prepared;
|
|
1691
1725
|
}
|
|
1692
1726
|
|
|
1693
|
-
function removeOpenCodeMcpConfig() {
|
|
1694
|
-
const updates = openCodeMcpConfigs().filter((config) => managedOpenCodeMcp(config.value?.mcp?.shifu));
|
|
1727
|
+
function removeOpenCodeMcpConfig(major) {
|
|
1728
|
+
const updates = openCodeMcpConfigs(major).filter((config) => managedOpenCodeMcp(config.value?.mcp?.shifu) || managedOpenCodeMcp(config.value?.mcp?.servers?.shifu));
|
|
1695
1729
|
for (const config of updates) {
|
|
1696
1730
|
if (!unchangedConfig(config)) throw new Error("OpenCode configuration changed during disconnect. Retry to preserve those changes.");
|
|
1697
|
-
|
|
1731
|
+
let candidate = config.original;
|
|
1732
|
+
if (managedOpenCodeMcp(config.value?.mcp?.shifu)) candidate = editOpenCodeMcp(candidate, undefined);
|
|
1733
|
+
if (managedOpenCodeMcp(config.value?.mcp?.servers?.shifu)) candidate = editOpenCodeMcp(candidate, undefined, 2);
|
|
1734
|
+
writePrivateText(config.file, candidate);
|
|
1698
1735
|
}
|
|
1699
1736
|
fs.rmSync(openCodeTokenPath(), { force: true });
|
|
1700
1737
|
}
|
|
@@ -1802,7 +1839,7 @@ function contextInstructionFile(harness) {
|
|
|
1802
1839
|
// Older clients fall back to XDG rules; current clients use the custom home.
|
|
1803
1840
|
let version;
|
|
1804
1841
|
try {
|
|
1805
|
-
version =
|
|
1842
|
+
version = openCodeVersion();
|
|
1806
1843
|
} catch { /* Diagnostics can contain settings; report only the remedy. */ }
|
|
1807
1844
|
if (!version || olderPackageVersion(version, "1.18.30")) throw new Error("OpenCode's custom instruction home conflicts with existing XDG rules. Upgrade to OpenCode 1.18.30 or later, or unset OPENCODE_CONFIG_DIR before MCP setup; nothing was changed.");
|
|
1808
1845
|
}
|
|
@@ -1899,17 +1936,18 @@ async function setupMcp(harness) {
|
|
|
1899
1936
|
if (!unchangedContextInstructions(instructions)) throw new Error("The global instructions changed during setup. Run mcp-setup again to preserve those changes.");
|
|
1900
1937
|
if (harness === "opencode") writePrivateText(openCodeTokenPath(), config.token);
|
|
1901
1938
|
writePrivateText(prepared.file, prepared.candidate);
|
|
1902
|
-
writeJSON(configPath(harness), { ...config, mcpUrl, ...(harness === "claude_code" ? { mcpHeadersHelper: helper } : {}) });
|
|
1939
|
+
writeJSON(configPath(harness), { ...config, mcpUrl, ...(harness === "opencode" ? { mcpConfigMajor: prepared.openCodeMajor } : {}), ...(harness === "claude_code" ? { mcpHeadersHelper: helper } : {}) });
|
|
1903
1940
|
writeContextInstructions(instructions);
|
|
1904
1941
|
console.error(`Verified Shifu MCP tools: ${tools.join(", ")}. ${HARNESS_NAMES[harness]} configuration and usage instructions are installed.`);
|
|
1905
1942
|
console.error(`The existing connection key is read ${harness === "opencode" ? "from a private credential file" : "by a local credential helper"}; it was not copied into MCP configuration. The sync endpoint and schedule were preserved.`);
|
|
1906
|
-
|
|
1943
|
+
const reload = prepared.openCodeMajor === 2 ? "Run opencode service stop, reopen OpenCode and start a new chat" : `Reload ${HARNESS_NAMES[harness]} or start a new chat`;
|
|
1944
|
+
console.error(`Proactive context guidance is installed at ${instructions.file}. ${reload} to load the MCP tools and instructions. This setup check does not prove the current chat has loaded them or enforce tool calls.`);
|
|
1907
1945
|
}
|
|
1908
1946
|
|
|
1909
1947
|
function disconnect(harness) {
|
|
1910
1948
|
const config = readConfig(harness);
|
|
1911
1949
|
if (fs.existsSync(lockPath(harness))) throw new Error("A Shifu sync is running. Try disconnecting again after it finishes.");
|
|
1912
|
-
if (harness === "opencode" && (config.mcpUrl || fs.existsSync(openCodeTokenPath()))) removeOpenCodeMcpConfig();
|
|
1950
|
+
if (harness === "opencode" && (config.mcpUrl || fs.existsSync(openCodeTokenPath()))) removeOpenCodeMcpConfig(config.mcpConfigMajor);
|
|
1913
1951
|
if (harness === "claude_code" && config.mcpUrl) removeClaudeMcpConfig(config.mcpHeadersHelper || helperCommand("claude_code"));
|
|
1914
1952
|
removeSchedule(harness);
|
|
1915
1953
|
for (const file of [configPath(harness), statePath(harness), pendingPath(harness)]) {
|
package/package.json
CHANGED
|
@@ -10,12 +10,12 @@ description: Retrieve relevant work context at substantive task starts and new t
|
|
|
10
10
|
When asked to connect Shifu context, run:
|
|
11
11
|
|
|
12
12
|
```sh
|
|
13
|
-
npx --yes @useshifu/coding-harness@0.3.
|
|
13
|
+
npx --yes @useshifu/coding-harness@0.3.23 mcp-setup --harness codex
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
For a branch deployment, append `--mcp-url` with the user's supplied HTTPS endpoint ending in `/mcp`. Keep the existing sync API endpoint. The CLI reuses this harness's saved key, checks the authenticated tools, and preserves existing settings. Codex and Claude Code use local credential helpers; OpenCode uses its native `{file:...}` substitution pointing to a private credential file. The key is never placed literally in MCP configuration. If no connection exists, the CLI asks for this harness's key in the terminal. Never request or print the key in chat or place it in command arguments. When input is unavailable, have the user run the command in an interactive terminal. Do not substitute plaintext credentials for an unsupported credential mechanism.
|
|
17
17
|
|
|
18
|
-
Setup also installs a managed read-only context policy in the harness’s native global instruction file, preserving existing instructions. Reload the harness or start a new chat after setup. Check that the tools are actually available before claiming this chat can use them. Setup supports local macOS/Linux connections; remote execution environments cannot read this device's credential helper or file. OpenCode
|
|
18
|
+
Setup also installs a managed read-only context policy in the harness’s native global instruction file, preserving existing instructions. Reload the harness or start a new chat after setup. Check that the tools are actually available before claiming this chat can use them. Setup supports local macOS/Linux connections; remote execution environments cannot read this device's credential helper or file. OpenCode setup detects 1.x or 2.x, writes the matching MCP shape and validates it through the installed client. V2 exposes Shifu tools directly and uses separate startup, catalog and execution budgets. The saved OpenCode key remains in its private credential file. After V2 setup, tell the user to run `opencode service stop`, reopen OpenCode and start a new chat; do not stop a running user service automatically. Claude Code requires HTTP MCP with `headersHelper` (verified with 2.1.295); setup validates it through the installed CLI. If Claude Code is outdated, help the user update it using official installation instructions before retrying. The connection uses user scope and honors `CLAUDE_CONFIG_DIR`. Restart Claude Code and start a new session, or use `/mcp` to reconnect after rotating the saved key. Unsupported versions or config schemas fail before MCP settings change.
|
|
19
19
|
|
|
20
20
|
## Consult context
|
|
21
21
|
|