pi-profile-switch 0.6.0 → 0.8.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
@@ -27,72 +27,62 @@ pi-profile ask -- --model openai/gpt-5.4
27
27
 
28
28
  ## Define your own profiles
29
29
 
30
- Profiles live in two JSON files, both optional:
30
+ Profiles live in two directories, with one JSON file per profile:
31
31
 
32
- | File | Scope |
32
+ | Path | Scope |
33
33
  | --- | --- |
34
- | `~/.pi-profile-switch/profiles.json` | Global, all projects. `PI_PROFILE_SWITCH_DIR` overrides the root; `~/.pi/agent/profiles.json` is read as a legacy fallback for migration. |
35
- | `<project>/.pi/profiles.json` | Project-level, trusted projects only. |
34
+ | `~/.pi-profile-switch/profiles/<name>.json` | Global, all projects. `PI_PROFILE_SWITCH_DIR` overrides the workspace root. |
35
+ | `<project>/.pi/profiles/<name>.json` | Project-level, trusted projects only. |
36
36
 
37
- Create or change a profile by editing the JSON directly — schema: [`schemas/profiles.schema.json`](schemas/profiles.schema.json).
37
+ Create or change a profile by editing or creating a `<name>.json` file directly — schema: [`schemas/profiles.schema.json`](schemas/profiles.schema.json).
38
38
 
39
- On install, pi-profile-switch seeds the global file with a starter **`ask`** profile — read-only Q&A and code exploration. It assumes nothing about your setup; edit or delete it freely:
39
+ On install, pi-profile-switch seeds the global `profiles/` directory with a starter **`ask`** profile (`ask.json`) — read-only Q&A and code exploration. It assumes nothing about your setup; edit or delete it freely:
40
40
 
41
41
  ```json
42
42
  {
43
- "schemaVersion": 1,
44
- "profiles": {
45
- "ask": {
46
- "label": "Ask & Discuss",
47
- "description": "Read-only Q&A and code exploration; no file modifications or command execution",
48
- "skills": [],
49
- "extensions": [],
50
- "tools": ["read", "grep", "find", "ls"],
51
- "instructions": "You are in read-only discussion mode. Answer questions and explain code without modifying any files or running shell commands."
52
- }
53
- }
43
+ "label": "Ask & Discuss",
44
+ "description": "Read-only Q&A and code exploration; no file modifications or command execution",
45
+ "skills": [],
46
+ "extensions": [],
47
+ "tools": ["read", "grep", "find", "ls"],
48
+ "instructions": "You are in read-only discussion mode. Answer questions and explain code without modifying any files or running shell commands."
54
49
  }
55
50
  ```
56
51
 
57
- One profile can use every field at once. This example `impl` profile loads the TDD skill, the mcp-scripting skill (shipped by pi-mcp-adapter), and your internal skills; wires up two MCP servers; allows the built-in tools plus both servers' MCP tools by glob; and pins the model and standing instructions:
52
+ One profile can use every field at once. This example `impl` profile (`impl.json`) loads the TDD skill, the mcp-scripting skill (shipped by pi-mcp-adapter), and your internal skills; wires up two MCP servers; allows the built-in tools plus both servers' MCP tools by glob; and pins the model and standing instructions:
58
53
 
59
54
  ```json
60
55
  {
61
- "schemaVersion": 1,
62
- "profiles": {
63
- "impl": {
64
- "label": "Implementation",
65
- "description": "Full-powered implementation profile: every available field, pinned model",
66
- "skills": [
67
- "tdd",
68
- "internal-*",
69
- "mcp-scripting"
70
- ],
71
- "extensions": [
72
- "pi-mcp-adapter"
73
- ],
74
- "mcps": [
75
- "github",
76
- "linear"
77
- ],
78
- "tools": [
79
- "read",
80
- "grep",
81
- "find",
82
- "ls",
83
- "bash",
84
- "edit",
85
- "write",
86
- "mcp__*",
87
- "github_*",
88
- "linear_*"
89
- ],
90
- "defaultProvider": "anthropic",
91
- "defaultModel": "claude-sonnet-4-5",
92
- "defaultThinkingLevel": "high",
93
- "instructions": "Prefer small, verifiable changes. Run the test suite before claiming completion."
94
- }
95
- }
56
+ "label": "Implementation",
57
+ "description": "Full-powered implementation profile: every available field, pinned model",
58
+ "skills": [
59
+ "tdd",
60
+ "internal-*",
61
+ "mcp-scripting"
62
+ ],
63
+ "extensions": [
64
+ "pi-mcp-adapter"
65
+ ],
66
+ "mcps": [
67
+ "github",
68
+ "linear"
69
+ ],
70
+ "tools": [
71
+ "read",
72
+ "grep",
73
+ "find",
74
+ "ls",
75
+ "bash",
76
+ "edit",
77
+ "write",
78
+ "mcp__*",
79
+ "github_*",
80
+ "linear_*"
81
+ ],
82
+ "defaultProvider": "anthropic",
83
+ "defaultModel": "claude-sonnet-4-5",
84
+ "defaultThinkingLevel": "high",
85
+ "instructions": "Prefer small, verifiable changes. Run the test suite before claiming completion."
96
86
  }
97
87
  ```
98
88
 
@@ -103,7 +93,15 @@ How fields resolve:
103
93
  - `mcps` references servers from your pi-mcp-adapter configuration; connection details stay in the adapter's own config.
104
94
  - Any field you omit keeps plain Pi behavior.
105
95
 
106
- The files in [`examples/`](examples/) mirror the two profiles above: `profiles.json` is the seeded starter, `example.json` the full-field demo.
96
+ The files in [`examples/`](examples/) mirror the two profiles above: `ask.json` is the seeded starter, `example.json` the full-field demo.
97
+
98
+ ### Migrating from earlier versions
99
+
100
+ If you used an earlier version that stored all profiles in a single `profiles.json` (`schemaVersion: 1`), migrate manually by creating a file for each profile under the `profiles/` directory:
101
+
102
+ 1. Create directory `~/.pi-profile-switch/profiles/` (or `<project>/.pi/profiles/`).
103
+ 2. For each key `<name>` in your old `profiles.json`'s `profiles` object, save its value directly as `<name>.json`.
104
+ 3. Drop the outer `schemaVersion` and `profiles` envelope.
107
105
 
108
106
  ## Commands
109
107
 
package/README.zh-CN.md CHANGED
@@ -27,72 +27,62 @@ pi-profile ask -- --model openai/gpt-5.4
27
27
 
28
28
  ## 自定义 profile
29
29
 
30
- profile 定义在两个 JSON 文件中,均可选:
30
+ profile 保存在两个目录中,每个 profile 对应一个独立 JSON 文件:
31
31
 
32
- | 文件 | 作用域 |
32
+ | 路径 | 作用域 |
33
33
  | --- | --- |
34
- | `~/.pi-profile-switch/profiles.json` | 全局,对所有项目生效。`PI_PROFILE_SWITCH_DIR` 可自定义根目录;`~/.pi/agent/profiles.json` 作为遗留路径向下兼容,用于迁移。 |
35
- | `<项目>/.pi/profiles.json` | 项目级,仅对已信任项目生效。 |
34
+ | `~/.pi-profile-switch/profiles/<name>.json` | 全局,对所有项目生效。`PI_PROFILE_SWITCH_DIR` 可自定义根目录。 |
35
+ | `<项目>/.pi/profiles/<name>.json` | 项目级,仅对已信任项目生效。 |
36
36
 
37
- 直接编辑 JSON 即可创建或修改 profile——schema 见 [`schemas/profiles.schema.json`](schemas/profiles.schema.json)。
37
+ 直接编辑或新建 `<name>.json` 即可创建或修改 profile——schema 见 [`schemas/profiles.schema.json`](schemas/profiles.schema.json)。
38
38
 
39
- 安装时,pi-profile-switch 会向全局文件播种一个初始 **`ask`** profile——只读的问答与代码走读模式。它不假设你安装过任何插件,可随意修改或删除:
39
+ 安装时,pi-profile-switch 会向全局 `profiles/` 目录播种一个初始 **`ask`** profile(`ask.json`)——只读的问答与代码走读模式。它不假设你安装过任何插件,可随意修改或删除:
40
40
 
41
41
  ```json
42
42
  {
43
- "schemaVersion": 1,
44
- "profiles": {
45
- "ask": {
46
- "label": "Ask & Discuss",
47
- "description": "Read-only Q&A and code exploration; no file modifications or command execution",
48
- "skills": [],
49
- "extensions": [],
50
- "tools": ["read", "grep", "find", "ls"],
51
- "instructions": "You are in read-only discussion mode. Answer questions and explain code without modifying any files or running shell commands."
52
- }
53
- }
43
+ "label": "Ask & Discuss",
44
+ "description": "Read-only Q&A and code exploration; no file modifications or command execution",
45
+ "skills": [],
46
+ "extensions": [],
47
+ "tools": ["read", "grep", "find", "ls"],
48
+ "instructions": "You are in read-only discussion mode. Answer questions and explain code without modifying any files or running shell commands."
54
49
  }
55
50
  ```
56
51
 
57
- 一个 profile 可以同时使用全部字段。下面这个 `impl` profile 示例加载 TDD skill、mcp-scripting skill(pi-mcp-adapter 自带)和你的内部 skills;接入两个 MCP server;tool 白名单用 glob 覆盖内建工具和这两个 server 的 MCP 工具;并钉住模型与常驻 instructions:
52
+ 一个 profile 可以同时使用全部字段。下面这个 `impl` profile 示例(`impl.json`)加载 TDD skill、mcp-scripting skill(pi-mcp-adapter 自带)和你的内部 skills;接入两个 MCP server;tool 白名单用 glob 覆盖内建工具和这两个 server 的 MCP 工具;并钉住模型与常驻 instructions:
58
53
 
59
54
  ```json
60
55
  {
61
- "schemaVersion": 1,
62
- "profiles": {
63
- "impl": {
64
- "label": "Implementation",
65
- "description": "Full-powered implementation profile: every available field, pinned model",
66
- "skills": [
67
- "tdd",
68
- "internal-*",
69
- "mcp-scripting"
70
- ],
71
- "extensions": [
72
- "pi-mcp-adapter"
73
- ],
74
- "mcps": [
75
- "github",
76
- "linear"
77
- ],
78
- "tools": [
79
- "read",
80
- "grep",
81
- "find",
82
- "ls",
83
- "bash",
84
- "edit",
85
- "write",
86
- "mcp__*",
87
- "github_*",
88
- "linear_*"
89
- ],
90
- "defaultProvider": "anthropic",
91
- "defaultModel": "claude-sonnet-4-5",
92
- "defaultThinkingLevel": "high",
93
- "instructions": "Prefer small, verifiable changes. Run the test suite before claiming completion."
94
- }
95
- }
56
+ "label": "Implementation",
57
+ "description": "Full-powered implementation profile: every available field, pinned model",
58
+ "skills": [
59
+ "tdd",
60
+ "internal-*",
61
+ "mcp-scripting"
62
+ ],
63
+ "extensions": [
64
+ "pi-mcp-adapter"
65
+ ],
66
+ "mcps": [
67
+ "github",
68
+ "linear"
69
+ ],
70
+ "tools": [
71
+ "read",
72
+ "grep",
73
+ "find",
74
+ "ls",
75
+ "bash",
76
+ "edit",
77
+ "write",
78
+ "mcp__*",
79
+ "github_*",
80
+ "linear_*"
81
+ ],
82
+ "defaultProvider": "anthropic",
83
+ "defaultModel": "claude-sonnet-4-5",
84
+ "defaultThinkingLevel": "high",
85
+ "instructions": "Prefer small, verifiable changes. Run the test suite before claiming completion."
96
86
  }
97
87
  ```
98
88
 
@@ -103,7 +93,15 @@ profile 定义在两个 JSON 文件中,均可选:
103
93
  - `mcps` 引用 pi-mcp-adapter 配置中的 server;连接细节留在 adapter 自己的配置里。
104
94
  - 未写的字段保持原生 Pi 行为。
105
95
 
106
- [`examples/`](examples/) 中的两个文件与上面一一对应:`profiles.json` 是播种的初始 profile,`example.json` 是全字段演示。
96
+ [`examples/`](examples/) 中的两个文件与上面一一对应:`ask.json` 是播种的初始 profile,`example.json` 是全字段演示。
97
+
98
+ ### 从旧版本迁移
99
+
100
+ 如果你之前使用了把全部 profile 存在单个 `profiles.json`(含 `schemaVersion: 1`)的旧版本,请手动把每个 profile 拆分到 `profiles/` 目录:
101
+
102
+ 1. 创建 `~/.pi-profile-switch/profiles/`(或 `<项目>/.pi/profiles/`)目录。
103
+ 2. 将旧 `profiles.json` 中 `profiles` 下的每个 `<name>` 键值提取为独立的 `<name>.json` 文件。
104
+ 3. 去除外层的 `schemaVersion` 与 `profiles` 信封,文件顶层即为裸 profile 定义。
107
105
 
108
106
  ## 命令
109
107
 
package/bin/pi-profile.ts CHANGED
@@ -37,10 +37,16 @@ try {
37
37
  console.error(`pi-profile: warning: ${warning}`);
38
38
  }
39
39
  // Stale per-launch instance dirs (dead pid, or no pid past the grace
40
- // window) are swept before this launch materializes its own. Directories
41
- // holding state pi-profile did not generate are kept and reported instead of
42
- // deleted (ADR-0010). Best-effort: sweep errors never block the launch.
43
- for (const warning of await sweepStaleInstances()) {
40
+ // window) are swept before this launch materializes its own. Unrecognized
41
+ // entries are dispositioned per content scan: kept + reported when they
42
+ // reference the instance path or cannot be cleared, adopted into the real
43
+ // agent dir, or deleted on a name conflict (real wins) — all with a stderr
44
+ // notice (ADR-0012). Best-effort: sweep errors never block the launch.
45
+ const sweep = await sweepStaleInstances(agentDir);
46
+ for (const notice of sweep.notices) {
47
+ console.error(`pi-profile: notice: ${notice}`);
48
+ }
49
+ for (const warning of sweep.warnings) {
44
50
  console.error(`pi-profile: warning: ${warning}`);
45
51
  }
46
52
  const generated = await generateRuntimeDir(plan, { agentDir, discovery, projectDir });
@@ -1,29 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * postinstall: seed the global catalog with the default profiles file.
3
+ * postinstall: seed the global catalog with the default starter profile.
4
4
  *
5
5
  * Runs at package install time (`npm install pi-profile-switch` / `pi install`).
6
6
  * Idempotent and conservative:
7
- * - Writes the shipped `examples/profiles.json` starter catalog to the
8
- * profile-switch dir ONLY when no
9
- * catalog exists there yet (COPYFILE_EXCL; an existing file — including
10
- * one written concurrently — is never touched).
11
- * - Skips entirely when a legacy `~/.pi/agent/profiles.json` exists, because
12
- * the resolver still falls back to it and a new preferred-path file would
13
- * silently shadow it (see src/workspace.ts resolveGlobalProfilesPath).
7
+ * - Writes the shipped `examples/ask.json` starter profile to the
8
+ * profiles dir ONLY when no .json profile exists there yet
9
+ * (COPYFILE_EXCL; an existing file — including one written concurrently — is never touched).
14
10
  * - Never fails the install: errors are downgraded to a warning.
15
11
  *
16
12
  * This module is plain Node ESM (no jiti/TS): npm may run postinstall in a
17
13
  * context where only plain JS is safe. The path rules intentionally mirror
18
14
  * src/workspace.ts — keep them in sync.
19
15
  */
20
- import { access, copyFile, mkdir } from "node:fs/promises";
16
+ import { copyFile, mkdir, readdir } from "node:fs/promises";
21
17
  import { constants } from "node:fs";
22
18
  import { homedir } from "node:os";
23
19
  import path from "node:path";
24
20
  import { fileURLToPath, pathToFileURL } from "node:url";
25
21
 
26
- const DEFAULT_TEMPLATE = fileURLToPath(new URL("../examples/profiles.json", import.meta.url));
22
+ const DEFAULT_TEMPLATE = fileURLToPath(new URL("../examples/ask.json", import.meta.url));
27
23
 
28
24
  /** Mirrors getProfileSwitchDir() in src/workspace.ts.
29
25
  * @param {NodeJS.ProcessEnv} env */
@@ -33,38 +29,40 @@ function profileSwitchDir(env) {
33
29
  return path.join(homedir(), ".pi-profile-switch");
34
30
  }
35
31
 
36
- /** The legacy migration fallback the resolver still reads (~/.pi/agent).
32
+ /** Mirrors getGlobalProfilesDir() in src/workspace.ts.
37
33
  * @param {NodeJS.ProcessEnv} env */
38
- function legacyCatalogPath(env) {
39
- const agentDir = env.PI_CODING_AGENT_DIR ?? path.join(homedir(), ".pi", "agent");
40
- return path.join(agentDir, "profiles.json");
34
+ function globalProfilesDir(env) {
35
+ return path.join(profileSwitchDir(env), "profiles");
41
36
  }
42
37
 
43
- /** @param {string} filePath */
44
- async function exists(filePath) {
38
+ /** Checks whether the directory exists and contains any .json files.
39
+ * @param {string} dir */
40
+ async function hasAnyJsonProfiles(dir) {
45
41
  try {
46
- await access(filePath);
47
- return true;
42
+ const entries = await readdir(dir);
43
+ return entries.some((name) => name.endsWith(".json"));
48
44
  } catch {
49
45
  return false;
50
46
  }
51
47
  }
52
48
 
53
- /** @typedef {{ path: string, written: boolean, skipped?: string }} InstallResult */
49
+ /** @typedef {{ path: string, written: boolean }} InstallResult */
54
50
 
55
51
  /**
56
- * Seeds the default catalog. Safe to call repeatedly; only the first call
57
- * writes.
52
+ * Seeds the default starter profile. Safe to call repeatedly; only writes
53
+ * if no .json files exist in the global profiles directory.
58
54
  * @param {{ env?: NodeJS.ProcessEnv }} [options]
59
55
  * @returns {Promise<InstallResult>}
60
56
  */
61
57
  export async function installDefaultProfiles({ env = process.env } = {}) {
62
- const target = path.join(profileSwitchDir(env), "profiles.json");
63
- if (await exists(target)) return { path: target, written: false };
64
- if (await exists(legacyCatalogPath(env))) {
65
- return { path: target, written: false, skipped: "legacy-catalog-present" };
58
+ const dir = globalProfilesDir(env);
59
+ const target = path.join(dir, "ask.json");
60
+
61
+ if (await hasAnyJsonProfiles(dir)) {
62
+ return { path: target, written: false };
66
63
  }
67
- await mkdir(path.dirname(target), { recursive: true });
64
+
65
+ await mkdir(dir, { recursive: true });
68
66
  try {
69
67
  await copyFile(DEFAULT_TEMPLATE, target, constants.COPYFILE_EXCL);
70
68
  } catch (error) {
@@ -80,10 +78,10 @@ const invokedDirectly = process.argv[1] !== undefined && import.meta.url === pat
80
78
  if (invokedDirectly) {
81
79
  installDefaultProfiles().then(
82
80
  (result) => {
83
- if (result.written) console.log(`pi-profile: seeded default profiles at ${result.path}`);
81
+ if (result.written) console.log(`pi-profile: seeded starter profile at ${result.path}`);
84
82
  },
85
83
  (error) => {
86
- console.warn(`pi-profile: could not seed default profiles: ${error instanceof Error ? error.message : error}`);
84
+ console.warn(`pi-profile: could not seed starter profile: ${error instanceof Error ? error.message : error}`);
87
85
  },
88
86
  );
89
87
  }
@@ -0,0 +1,13 @@
1
+ {
2
+ "label": "Ask & Discuss",
3
+ "description": "Read-only Q&A and code exploration; no file modifications or command execution",
4
+ "skills": [],
5
+ "extensions": [],
6
+ "tools": [
7
+ "read",
8
+ "grep",
9
+ "find",
10
+ "ls"
11
+ ],
12
+ "instructions": "You are in read-only discussion mode. Answer questions and explain code without modifying any files or running shell commands."
13
+ }
@@ -1,37 +1,32 @@
1
1
  {
2
- "schemaVersion": 1,
3
- "profiles": {
4
- "impl": {
5
- "label": "Implementation",
6
- "description": "Full-powered implementation profile: every available field, pinned model",
7
- "skills": [
8
- "tdd",
9
- "internal-*",
10
- "mcp-scripting"
11
- ],
12
- "extensions": [
13
- "pi-mcp-adapter"
14
- ],
15
- "mcps": [
16
- "github",
17
- "linear"
18
- ],
19
- "tools": [
20
- "read",
21
- "grep",
22
- "find",
23
- "ls",
24
- "bash",
25
- "edit",
26
- "write",
27
- "mcp__*",
28
- "github_*",
29
- "linear_*"
30
- ],
31
- "defaultProvider": "anthropic",
32
- "defaultModel": "claude-sonnet-4-5",
33
- "defaultThinkingLevel": "high",
34
- "instructions": "Prefer small, verifiable changes. Run the test suite before claiming completion."
35
- }
36
- }
2
+ "label": "Implementation",
3
+ "description": "Full-powered implementation profile: every available field, pinned model",
4
+ "skills": [
5
+ "tdd",
6
+ "internal-*",
7
+ "mcp-scripting"
8
+ ],
9
+ "extensions": [
10
+ "pi-mcp-adapter"
11
+ ],
12
+ "mcps": [
13
+ "github",
14
+ "linear"
15
+ ],
16
+ "tools": [
17
+ "read",
18
+ "grep",
19
+ "find",
20
+ "ls",
21
+ "bash",
22
+ "edit",
23
+ "write",
24
+ "mcp__*",
25
+ "github_*",
26
+ "linear_*"
27
+ ],
28
+ "defaultProvider": "anthropic",
29
+ "defaultModel": "claude-sonnet-4-5",
30
+ "defaultThinkingLevel": "high",
31
+ "instructions": "Prefer small, verifiable changes. Run the test suite before claiming completion."
37
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-profile-switch",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Named profiles for Pi: reference skills, extensions, MCP servers, and tools per workflow, switched without restarting. Install: npm install -g pi-profile-switch (not pi install).",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -1,86 +1,60 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "title": "pi-profile-switch profile catalog",
4
- "description": "Named profile definitions (global ~/.pi-profile-switch/profiles.json, legacy fallback ~/.pi/agent/profiles.json; or project .pi/profiles.json). Definitions are complete and self-contained: there is no inheritance field, and resource references are names/globs, never copies. The built-in \"default\" profile must not be defined here.",
3
+ "title": "pi-profile-switch profile definition",
4
+ "description": "A named profile definition stored in ~/.pi-profile-switch/profiles/<name>.json or <project>/.pi/profiles/<name>.json. Definitions are complete and self-contained: there is no inheritance field, and resource references are names/globs, never copies.",
5
5
  "type": "object",
6
- "required": [
7
- "schemaVersion",
8
- "profiles"
9
- ],
10
6
  "additionalProperties": false,
11
7
  "properties": {
12
- "schemaVersion": {
13
- "const": 1
8
+ "label": {
9
+ "type": "string",
10
+ "description": "Display label in the selector and /profile list."
14
11
  },
15
- "profiles": {
16
- "type": "object",
17
- "propertyNames": {
18
- "not": {
19
- "const": "default"
20
- }
12
+ "description": {
13
+ "type": "string"
14
+ },
15
+ "skills": {
16
+ "type": "array",
17
+ "items": {
18
+ "type": "string"
21
19
  },
22
- "additionalProperties": {
23
- "$ref": "#/$defs/profile"
24
- }
25
- }
26
- },
27
- "$defs": {
28
- "profile": {
29
- "type": "object",
30
- "additionalProperties": false,
31
- "properties": {
32
- "label": {
33
- "type": "string",
34
- "description": "Display label in the selector and /profile list."
35
- },
36
- "description": {
37
- "type": "string"
38
- },
39
- "skills": {
40
- "type": "array",
41
- "items": {
42
- "type": "string"
43
- },
44
- "description": "Skill names or globs (e.g. \"review\", \"internal-*\") referencing discovered skills."
45
- },
46
- "extensions": {
47
- "type": "array",
48
- "items": {
49
- "type": "string"
50
- },
51
- "description": "Extension names or globs. Package names, source aliases, loose-file stems, glob patterns, or direct file paths, resolved against discovered extensions."
52
- },
53
- "mcps": {
54
- "type": "array",
55
- "items": {
56
- "type": "string"
57
- },
58
- "description": "MCP server names or globs, discovered by pi-mcp-adapter configuration. Connection details stay in adapter-managed config."
59
- },
60
- "tools": {
61
- "type": "array",
62
- "items": {
63
- "type": "string"
64
- },
65
- "description": "Tool names or globs expanded against Pi's live registry (including extension tools)."
66
- },
67
- "defaultProvider": {
68
- "type": "string",
69
- "description": "Startup provider for this profile (e.g. \"anthropic\", \"openai\"). Mirrors Pi's settings.defaultProvider."
70
- },
71
- "defaultModel": {
72
- "type": "string",
73
- "description": "Startup model ID for this profile. Mirrors Pi's settings.defaultModel."
74
- },
75
- "defaultThinkingLevel": {
76
- "type": "string",
77
- "description": "Startup thinking level for this profile. Mirrors Pi's settings.defaultThinkingLevel."
78
- },
79
- "instructions": {
80
- "type": "string",
81
- "description": "Appended to Pi's fully built system prompt on every turn."
82
- }
83
- }
20
+ "description": "Skill names or globs (e.g. \"review\", \"internal-*\") referencing discovered skills."
21
+ },
22
+ "extensions": {
23
+ "type": "array",
24
+ "items": {
25
+ "type": "string"
26
+ },
27
+ "description": "Extension names or globs. Package names, source aliases, loose-file stems, glob patterns, or direct file paths, resolved against discovered extensions."
28
+ },
29
+ "mcps": {
30
+ "type": "array",
31
+ "items": {
32
+ "type": "string"
33
+ },
34
+ "description": "MCP server names or globs, discovered by pi-mcp-adapter configuration. Connection details stay in adapter-managed config."
35
+ },
36
+ "tools": {
37
+ "type": "array",
38
+ "items": {
39
+ "type": "string"
40
+ },
41
+ "description": "Tool names or globs expanded against Pi's live registry (including extension tools)."
42
+ },
43
+ "defaultProvider": {
44
+ "type": "string",
45
+ "description": "Startup provider for this profile (e.g. \"anthropic\", \"openai\"). Mirrors Pi's settings.defaultProvider."
46
+ },
47
+ "defaultModel": {
48
+ "type": "string",
49
+ "description": "Startup model ID for this profile. Mirrors Pi's settings.defaultModel."
50
+ },
51
+ "defaultThinkingLevel": {
52
+ "type": "string",
53
+ "description": "Startup thinking level for this profile. Mirrors Pi's settings.defaultThinkingLevel."
54
+ },
55
+ "instructions": {
56
+ "type": "string",
57
+ "description": "Appended to Pi's fully built system prompt on every turn."
84
58
  }
85
59
  }
86
60
  }