@withone/cli 1.28.0 → 1.29.0

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 CHANGED
@@ -124,15 +124,22 @@ Set up your API key and install the MCP server into your AI agents.
124
124
  one init
125
125
  ```
126
126
 
127
- Supports Claude Code, Claude Desktop, Cursor, Windsurf, Codex, and Kiro. Installs globally by default, or per-project with `-p` so your team can share configs (each person uses their own API key).
127
+ Supports Claude Code, Claude Desktop, Cursor, Windsurf, Codex, and Kiro.
128
128
 
129
- If you've already set up, `one init` shows your current status and lets you update your key, install to more agents, or reconfigure.
129
+ **Global vs. project scope.** `one init` is interactive and asks where the setup should live:
130
+
131
+ - **Global** (`~/.one/config.json`) — applies to every folder. Best when you only need one workspace / API key.
132
+ - **Project** (`~/.one/projects/<slug>/config.json`) — scoped to the current project, stored under your home directory so secrets never land in git. Use this when different projects need different API keys, connections, or access control.
133
+
134
+ When you run `one` in a project, it uses the project config if one exists and falls back to the global config otherwise. Use `one config path` to see which config is active and the full resolution order.
135
+
136
+ If you've already set up, `one init` shows your current status for the active scope and lets you update your key, install to more agents, or reconfigure.
130
137
 
131
138
  | Flag | What it does |
132
139
  |------|-------------|
133
140
  | `-y` | Skip confirmations |
134
- | `-g` | Install globally (default) |
135
- | `-p` | Install for current project only |
141
+ | `-g` | Non-interactive: write the One config globally (`~/.one/config.json`) |
142
+ | `-p` | Non-interactive: write the One config for this project (`~/.one/projects/<slug>/config.json`) |
136
143
 
137
144
  ### `one add <platform>`
138
145
 
package/dist/index.js CHANGED
@@ -36,24 +36,88 @@ import path from "path";
36
36
  import os from "os";
37
37
  var CONFIG_DIR = path.join(os.homedir(), ".one");
38
38
  var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
39
- function getConfigPath() {
40
- return CONFIG_FILE;
39
+ var PROJECTS_DIR = path.join(CONFIG_DIR, "projects");
40
+ function getProjectRoot(cwd = process.cwd()) {
41
+ let dir = path.resolve(cwd);
42
+ const root = path.parse(dir).root;
43
+ while (dir !== root) {
44
+ if (fs.existsSync(path.join(dir, ".git")) || fs.existsSync(path.join(dir, "package.json"))) {
45
+ return dir;
46
+ }
47
+ dir = path.dirname(dir);
48
+ }
49
+ return path.resolve(cwd);
41
50
  }
42
- function configExists() {
43
- return fs.existsSync(CONFIG_FILE);
51
+ function getProjectSlug(projectRoot = getProjectRoot()) {
52
+ return projectRoot.replace(/[\\/]/g, "-");
44
53
  }
45
- function readConfig() {
46
- if (!configExists()) {
47
- return null;
54
+ function getProjectConfigDir(projectRoot = getProjectRoot()) {
55
+ return path.join(PROJECTS_DIR, getProjectSlug(projectRoot));
56
+ }
57
+ function getProjectConfigPath(projectRoot = getProjectRoot()) {
58
+ return path.join(getProjectConfigDir(projectRoot), "config.json");
59
+ }
60
+ function getGlobalConfigPath() {
61
+ return CONFIG_FILE;
62
+ }
63
+ function resolveConfig() {
64
+ const projectRoot = getProjectRoot();
65
+ const projectSlug = getProjectSlug(projectRoot);
66
+ const projectPath = getProjectConfigPath(projectRoot);
67
+ if (fs.existsSync(projectPath)) {
68
+ const config2 = readConfigFile(projectPath);
69
+ if (config2) {
70
+ return { config: config2, scope: "project", path: projectPath, projectRoot, projectSlug };
71
+ }
48
72
  }
73
+ if (fs.existsSync(CONFIG_FILE)) {
74
+ const config2 = readConfigFile(CONFIG_FILE);
75
+ if (config2) {
76
+ return { config: config2, scope: "global", path: CONFIG_FILE, projectRoot, projectSlug };
77
+ }
78
+ }
79
+ return { config: null, scope: null, path: CONFIG_FILE, projectRoot, projectSlug };
80
+ }
81
+ function readConfigFile(filePath) {
49
82
  try {
50
- const content = fs.readFileSync(CONFIG_FILE, "utf-8");
83
+ const content = fs.readFileSync(filePath, "utf-8");
51
84
  return JSON.parse(content);
52
85
  } catch {
53
86
  return null;
54
87
  }
55
88
  }
56
- function writeConfig(config2) {
89
+ function configExists() {
90
+ return resolveConfig().config !== null;
91
+ }
92
+ function globalConfigExists() {
93
+ return fs.existsSync(CONFIG_FILE);
94
+ }
95
+ function projectConfigExists(projectRoot = getProjectRoot()) {
96
+ return fs.existsSync(getProjectConfigPath(projectRoot));
97
+ }
98
+ function readConfig() {
99
+ return resolveConfig().config;
100
+ }
101
+ function readGlobalConfig() {
102
+ if (!fs.existsSync(CONFIG_FILE)) return null;
103
+ return readConfigFile(CONFIG_FILE);
104
+ }
105
+ function readProjectConfig() {
106
+ const projectPath = getProjectConfigPath();
107
+ if (!fs.existsSync(projectPath)) return null;
108
+ return readConfigFile(projectPath);
109
+ }
110
+ function writeConfig(config2, scope) {
111
+ const targetScope = scope ?? resolveConfig().scope ?? "global";
112
+ if (targetScope === "project") {
113
+ const dir = getProjectConfigDir();
114
+ if (!fs.existsSync(dir)) {
115
+ fs.mkdirSync(dir, { recursive: true, mode: 448 });
116
+ }
117
+ const filePath = getProjectConfigPath();
118
+ fs.writeFileSync(filePath, JSON.stringify(config2, null, 2), { mode: 384 });
119
+ return;
120
+ }
57
121
  if (!fs.existsSync(CONFIG_DIR)) {
58
122
  fs.mkdirSync(CONFIG_DIR, { mode: 448 });
59
123
  }
@@ -108,10 +172,6 @@ function getAccessControl() {
108
172
  }
109
173
  var DEFAULT_API_BASE = "https://api.withone.ai/v1";
110
174
  function getApiBase() {
111
- const envBase = process.env.ONE_API_BASE;
112
- if (envBase) return `${envBase.replace(/\/+$/, "").replace(/\/v1$/, "")}/v1`;
113
- const rc = readOneRc();
114
- if (rc.ONE_API_BASE) return `${rc.ONE_API_BASE.replace(/\/+$/, "").replace(/\/v1$/, "")}/v1`;
115
175
  const config2 = readConfig();
116
176
  if (config2?.apiBase) return `${config2.apiBase}/v1`;
117
177
  return DEFAULT_API_BASE;
@@ -883,24 +943,98 @@ async function initCommand(options) {
883
943
  if (isAgentMode()) {
884
944
  error("This command requires interactive input. Run without --agent.");
885
945
  }
886
- const existingConfig = readConfig();
887
946
  printBanner();
947
+ const scope = await chooseConfigScope(options);
948
+ if (scope === null) {
949
+ p3.cancel("Setup cancelled.");
950
+ return;
951
+ }
952
+ const existingConfig = scope === "project" ? readProjectConfig() : readGlobalConfig();
888
953
  if (existingConfig) {
889
- await handleExistingConfig(existingConfig.apiKey, options);
954
+ await handleExistingConfig(existingConfig.apiKey, scope, options);
890
955
  return;
891
956
  }
892
- await freshSetup(options);
957
+ await freshSetup(scope, options);
958
+ }
959
+ async function chooseConfigScope(options) {
960
+ if (options.global) return "global";
961
+ if (options.project) return "project";
962
+ const resolved = resolveConfig();
963
+ const hasGlobal = globalConfigExists();
964
+ const hasProject = projectConfigExists();
965
+ const projectRoot = resolved.projectRoot;
966
+ const projectName = path4.basename(projectRoot);
967
+ const homeGlobal = tildify(getGlobalConfigPath());
968
+ const homeProject = tildify(getProjectConfigPath(projectRoot));
969
+ if (hasProject) {
970
+ console.log();
971
+ console.log(` ${pc2.dim("Project:")} ${projectName} ${pc2.dim(projectRoot)}`);
972
+ console.log(` ${pc2.bold("Active config:")} ${pc2.cyan("project")} ${pc2.dim("\xB7 " + homeProject)}`);
973
+ console.log();
974
+ if (hasGlobal) {
975
+ const which2 = await p3.select({
976
+ message: "Which config do you want to edit?",
977
+ options: [
978
+ { value: "project", label: `This project (${projectName})`, hint: homeProject },
979
+ { value: "global", label: "Global (all folders)", hint: homeGlobal }
980
+ ],
981
+ initialValue: "project"
982
+ });
983
+ if (p3.isCancel(which2)) return null;
984
+ return which2;
985
+ }
986
+ return "project";
987
+ }
988
+ console.log();
989
+ console.log(` ${pc2.bold("Initializing One")}`);
990
+ console.log(` ${pc2.dim("\u2500".repeat(42))}`);
991
+ console.log(` ${pc2.dim("Project:")} ${projectName} ${pc2.dim(projectRoot)}`);
992
+ console.log(` ${pc2.dim("Global:")} ${hasGlobal ? pc2.green("\u2713 configured") : pc2.yellow("\u2014 not set up")} ${pc2.dim(homeGlobal)}`);
993
+ console.log(` ${pc2.dim("Project:")} ${pc2.yellow("\u2014 not set up")} ${pc2.dim(homeProject)}`);
994
+ console.log();
995
+ const defaultScope = hasGlobal ? "project" : "global";
996
+ const hint = hasGlobal ? "Your global config stays as-is. This folder gets its own setup." : "No global config yet \u2014 this becomes your default for every folder.";
997
+ p3.note(hint, defaultScope === "project" ? "Recommended: project" : "Recommended: global");
998
+ const which = await p3.select({
999
+ message: "Where should this setup live?",
1000
+ options: [
1001
+ {
1002
+ value: "project",
1003
+ label: `This project only (${projectName})`,
1004
+ hint: "different API key / connections just for this folder"
1005
+ },
1006
+ {
1007
+ value: "global",
1008
+ label: "Globally (all folders)",
1009
+ hint: "applies everywhere you run `one`"
1010
+ }
1011
+ ],
1012
+ initialValue: defaultScope
1013
+ });
1014
+ if (p3.isCancel(which)) return null;
1015
+ return which;
1016
+ }
1017
+ function tildify(filePath) {
1018
+ const home = os4.homedir();
1019
+ return filePath.startsWith(home) ? "~" + filePath.slice(home.length) : filePath;
1020
+ }
1021
+ function scopeLabel(scope) {
1022
+ return scope === "project" ? pc2.cyan("[project]") : pc2.magenta("[global]");
893
1023
  }
894
- async function handleExistingConfig(apiKey, options) {
1024
+ function scopedMessage(scope, message) {
1025
+ return `${scopeLabel(scope)} ${message}`;
1026
+ }
1027
+ async function handleExistingConfig(apiKey, scope, options) {
895
1028
  const statuses = getAgentStatuses();
896
1029
  const masked = maskApiKey(apiKey);
897
1030
  const skillInstalled = isSkillInstalled2();
1031
+ const activeConfigPath = scope === "project" ? getProjectConfigPath() : getGlobalConfigPath();
898
1032
  console.log();
899
- console.log(` ${pc2.bold("Current Setup")}`);
1033
+ console.log(` ${pc2.bold("Current Setup")} ${scopeLabel(scope)}`);
900
1034
  console.log(` ${pc2.dim("\u2500".repeat(42))}`);
901
1035
  console.log(` ${pc2.dim("API Key:")} ${masked}`);
902
1036
  console.log(` ${pc2.dim("Skill:")} ${skillInstalled ? pc2.green("installed") : pc2.yellow("not installed")}`);
903
- console.log(` ${pc2.dim("Config:")} ${getConfigPath()}`);
1037
+ console.log(` ${pc2.dim("Config:")} ${tildify(activeConfigPath)}`);
904
1038
  const ac = getAccessControl();
905
1039
  if (Object.keys(ac).length > 0) {
906
1040
  console.log();
@@ -942,7 +1076,7 @@ async function handleExistingConfig(apiKey, options) {
942
1076
  label: "Start fresh (reconfigure everything)"
943
1077
  });
944
1078
  const action = await p3.select({
945
- message: "What would you like to do?",
1079
+ message: scopedMessage(scope, "What would you like to do?"),
946
1080
  options: actionOptions
947
1081
  });
948
1082
  if (p3.isCancel(action)) {
@@ -969,21 +1103,21 @@ async function handleExistingConfig(apiKey, options) {
969
1103
  p3.outro("Done.");
970
1104
  break;
971
1105
  case "update-key":
972
- await handleUpdateKey(statuses);
1106
+ await handleUpdateKey(statuses, scope);
973
1107
  break;
974
1108
  case "access-control":
975
1109
  await configCommand();
976
1110
  break;
977
1111
  case "start-fresh":
978
- await freshSetup({ yes: true });
1112
+ await freshSetup(scope, { yes: true });
979
1113
  break;
980
1114
  }
981
1115
  }
982
- async function handleUpdateKey(statuses) {
1116
+ async function handleUpdateKey(statuses, scope) {
983
1117
  p3.note(`Get your API key at:
984
- ${pc2.cyan(getApiKeyUrl())}`, "API Key");
1118
+ ${pc2.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
985
1119
  const openBrowser = await p3.confirm({
986
- message: "Open browser to get API key?",
1120
+ message: scopedMessage(scope, "Open browser to get API key?"),
987
1121
  initialValue: true
988
1122
  });
989
1123
  if (p3.isCancel(openBrowser)) {
@@ -994,7 +1128,7 @@ ${pc2.cyan(getApiKeyUrl())}`, "API Key");
994
1128
  await openApiKeyPage();
995
1129
  }
996
1130
  const newKey = await p3.text({
997
- message: "Enter your new One API key:",
1131
+ message: scopedMessage(scope, "Enter your new One API key:"),
998
1132
  placeholder: "sk_live_...",
999
1133
  validate: (value) => {
1000
1134
  if (!value) return "API key is required";
@@ -1030,13 +1164,18 @@ ${pc2.cyan(getApiKeyUrl())}`, "API Key");
1030
1164
  reinstalled.push(`${s.agent.name} (project)`);
1031
1165
  }
1032
1166
  }
1033
- const config2 = readConfig();
1034
- writeConfig({
1035
- apiKey: newKey,
1036
- installedAgents: config2?.installedAgents ?? [],
1037
- createdAt: config2?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1038
- accessControl: config2?.accessControl
1039
- });
1167
+ const current = scope === "project" ? readProjectConfig() : readGlobalConfig();
1168
+ writeConfig(
1169
+ {
1170
+ apiKey: newKey,
1171
+ installedAgents: current?.installedAgents ?? [],
1172
+ createdAt: current?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1173
+ accessControl: current?.accessControl,
1174
+ apiBase: current?.apiBase,
1175
+ cacheTtl: current?.cacheTtl
1176
+ },
1177
+ scope
1178
+ );
1040
1179
  if (reinstalled.length > 0) {
1041
1180
  p3.log.success(`Updated MCP configs: ${reinstalled.join(", ")}`);
1042
1181
  }
@@ -1199,11 +1338,11 @@ function printOnboardingPrompt() {
1199
1338
  console.log(pc2.cyan(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1200
1339
  console.log();
1201
1340
  }
1202
- async function freshSetup(options) {
1341
+ async function freshSetup(scope, options) {
1203
1342
  p3.note(`Get your API key at:
1204
- ${pc2.cyan(getApiKeyUrl())}`, "API Key");
1343
+ ${pc2.cyan(getApiKeyUrl())}`, `API Key ${scopeLabel(scope)}`);
1205
1344
  const openBrowser = await p3.confirm({
1206
- message: "Open browser to get API key?",
1345
+ message: scopedMessage(scope, "Open browser to get API key?"),
1207
1346
  initialValue: true
1208
1347
  });
1209
1348
  if (p3.isCancel(openBrowser)) {
@@ -1214,7 +1353,7 @@ ${pc2.cyan(getApiKeyUrl())}`, "API Key");
1214
1353
  await openApiKeyPage();
1215
1354
  }
1216
1355
  const apiKey = await p3.text({
1217
- message: "Enter your One API key:",
1356
+ message: scopedMessage(scope, "Enter your One API key:"),
1218
1357
  placeholder: "sk_live_...",
1219
1358
  validate: (value) => {
1220
1359
  if (!value) return "API key is required";
@@ -1238,15 +1377,24 @@ ${pc2.cyan(getApiKeyUrl())}`, "API Key");
1238
1377
  process.exit(1);
1239
1378
  }
1240
1379
  spinner5.stop("API key validated");
1241
- writeConfig({
1242
- apiKey,
1243
- installedAgents: [],
1244
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
1245
- });
1380
+ writeConfig(
1381
+ {
1382
+ apiKey,
1383
+ installedAgents: [],
1384
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
1385
+ },
1386
+ scope
1387
+ );
1246
1388
  await promptSkillInstall();
1247
1389
  await promptConnectIntegrations(apiKey);
1390
+ const savedPath = scope === "project" ? getProjectConfigPath() : getGlobalConfigPath();
1391
+ const resolutionHint = scope === "project" ? `When you run ${pc2.cyan("one")} from ${pc2.bold(path4.basename(getProjectRoot()))}, it uses this project config.
1392
+ From anywhere else, it falls back to your global config.` : `This config applies to every folder unless a project config is set.`;
1248
1393
  p3.note(
1249
- `Config saved to: ${pc2.dim(getConfigPath())}`,
1394
+ `${scopeLabel(scope)} Config saved to:
1395
+ ${pc2.dim(tildify(savedPath))}
1396
+
1397
+ ${resolutionHint}`,
1250
1398
  "Setup Complete"
1251
1399
  );
1252
1400
  printOnboardingPrompt();
@@ -3874,7 +4022,7 @@ var GUIDE_OVERVIEW = `# One CLI \u2014 Agent Guide
3874
4022
 
3875
4023
  ## Setup
3876
4024
 
3877
- 1. Run \`one init\` to configure your API key
4025
+ 1. Run \`one init\` to configure your API key (interactive \u2014 can be global or per-project)
3878
4026
  2. Run \`one add <platform>\` to connect platforms via OAuth
3879
4027
  3. Run \`one --agent connection list\` to verify connections
3880
4028
 
@@ -4654,12 +4802,46 @@ program.hook("postAction", async () => {
4654
4802
  if (!isNewerVersion(info.version, current)) return;
4655
4803
  autoUpdate(info.version, info.publishedAt);
4656
4804
  });
4657
- program.command("init").description("Set up One and install MCP to your AI agents").option("-y, --yes", "Skip confirmations").option("-g, --global", "Install MCP globally (available in all projects)").option("-p, --project", "Install MCP for this project only (creates .mcp.json)").action(async (options) => {
4805
+ program.command("init").description("Set up One and install MCP to your AI agents (interactive: picks global or project scope)").option("-y, --yes", "Skip confirmations").option("-g, --global", "Write the One config globally (~/.one/config.json) \u2014 skips the scope picker").option("-p, --project", "Write the One config for this project only (~/.one/projects/<slug>/) \u2014 skips the scope picker").action(async (options) => {
4658
4806
  await initCommand(options);
4659
4807
  });
4660
4808
  var config = program.command("config").description("Configure the CLI (access control, skills, ...)").action(async () => {
4661
4809
  await configCommand();
4662
4810
  });
4811
+ config.command("path").description("Show the active config path, scope, and the fallback chain (project \u2192 global)").action(() => {
4812
+ const resolved = resolveConfig();
4813
+ const globalPath = getGlobalConfigPath();
4814
+ const projectPath = getProjectConfigPath(resolved.projectRoot);
4815
+ const hasGlobal = globalConfigExists();
4816
+ const hasProject = projectConfigExists(resolved.projectRoot);
4817
+ if (isAgentMode()) {
4818
+ json({
4819
+ command: "config path",
4820
+ scope: resolved.scope,
4821
+ path: resolved.path,
4822
+ projectRoot: resolved.projectRoot,
4823
+ projectSlug: resolved.projectSlug,
4824
+ fallback: {
4825
+ project: { path: projectPath, exists: hasProject },
4826
+ global: { path: globalPath, exists: hasGlobal }
4827
+ }
4828
+ });
4829
+ return;
4830
+ }
4831
+ if (!resolved.scope) {
4832
+ console.log("No One config found.");
4833
+ console.log(` project: ${projectPath} (not set up)`);
4834
+ console.log(` global: ${globalPath} (not set up)`);
4835
+ console.log("\nRun 'one init' to get started.");
4836
+ return;
4837
+ }
4838
+ console.log(`Active: ${resolved.scope}`);
4839
+ console.log(`Path: ${resolved.path}`);
4840
+ console.log(`
4841
+ Resolution order (first match wins):`);
4842
+ console.log(` 1. project ${projectPath} ${hasProject ? "\u2713" : "\u2014"}`);
4843
+ console.log(` 2. global ${globalPath} ${hasGlobal ? "\u2713" : "\u2014"}`);
4844
+ });
4663
4845
  var configSkills = config.command("skills").description("Manage locally-installed skill files");
4664
4846
  configSkills.command("sync").description("Re-copy packaged skill files over the local install (runs automatically after CLI upgrades)").action(async () => {
4665
4847
  const result = forceSyncSkills();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withone/cli",
3
- "version": "1.28.0",
3
+ "version": "1.29.0",
4
4
  "description": "CLI for managing One",
5
5
  "type": "module",
6
6
  "files": [
@@ -22,6 +22,8 @@ description: |
22
22
 
23
23
  You have access to the One CLI which lets you interact with 250+ third-party platforms through their APIs. Always include the `--agent` flag right after `one` for structured JSON output.
24
24
 
25
+ If the user wants a separate API key / connections for a specific project (vs. their default), walk them through running `one init` from that project folder and picking the "project" scope — see `references/scoping.md`.
26
+
25
27
  ## Core Workflow: search -> knowledge -> execute
26
28
 
27
29
  Always follow this sequence when the user wants to do something on a connected platform:
@@ -0,0 +1,35 @@
1
+ # Project vs. global config
2
+
3
+ The One CLI can be configured at two scopes:
4
+
5
+ - **Global** — `~/.one/config.json`. Applies everywhere the user runs `one`.
6
+ - **Project** — `~/.one/projects/<slug>/config.json`, where `<slug>` is the project root path with slashes replaced by dashes (e.g. `/Users/jane/acme` → `-Users-jane-acme`). Only applies when running `one` from inside that project folder.
7
+
8
+ **Resolution order:** env vars → `.onerc` in cwd → project config → global config. Project config wins when present; otherwise the CLI falls back to the global config.
9
+
10
+ ## When to suggest project scope
11
+
12
+ Suggest project scope when the user wants any of the following for a specific folder only, without changing their default setup:
13
+
14
+ - A different One API key (e.g. sandbox workspace for a client project)
15
+ - A different set of connections / connection keys
16
+ - Different access control (permissions, scoped connections, knowledge-only mode)
17
+
18
+ ## How to set it up
19
+
20
+ Do **not** hand-edit `.onerc` or config files. Walk the user through the interactive init:
21
+
22
+ ```bash
23
+ cd /path/to/the/project
24
+ one init
25
+ ```
26
+
27
+ When `init` asks "Where should this setup live?", pick **"This project only"**. Init will write the config to `~/.one/projects/<slug>/config.json` and everything else (skill install, MCP) stays untouched.
28
+
29
+ To see which config is currently active and the full fallback chain:
30
+
31
+ ```bash
32
+ one --agent config path
33
+ ```
34
+
35
+ To switch an existing project back to using the global config, delete its project config file — the CLI will automatically fall back to global on the next run.