@agimon-ai/doompi-profile 0.0.1-alpha.6 → 0.0.1-alpha.7
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 +30 -10
- package/dist/adapters/pi/extension.cjs +1 -1
- package/dist/adapters/pi/extension.cjs.map +1 -1
- package/dist/adapters/pi/extension.d.cts.map +1 -1
- package/dist/adapters/pi/extension.d.mts.map +1 -1
- package/dist/adapters/pi/extension.mjs +1 -1
- package/dist/adapters/pi/extension.mjs.map +1 -1
- package/llms.txt +8 -3
- package/package.json +8 -7
- package/src/prompts/doompi-author-profile/SKILL.md +20 -0
- package/src/prompts/doompi-author-profile/references/profiles-contract.md +100 -0
package/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
Persona and environment profile switching for [DoomPi](https://www.npmjs.com/package/@agimon-ai/doompi)
|
|
4
4
|
sessions.
|
|
5
5
|
|
|
6
|
-
A **profile** is one of the four axes of a DoomPi selection, alongside domains, the major mode
|
|
7
|
-
the minor modes. It names a persona directory and a set of environment defaults:
|
|
6
|
+
A **profile** is one of the four axes of a DoomPi selection, alongside domains, the major mode,
|
|
7
|
+
and the minor modes. It names a persona directory and a set of environment defaults:
|
|
8
8
|
|
|
9
9
|
```yaml
|
|
10
10
|
# .doom/profiles.yaml
|
|
@@ -17,21 +17,21 @@ profiles:
|
|
|
17
17
|
REVIEW_STRICTNESS: high
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
The persona is `profile.md`, `SOUL.md
|
|
20
|
+
The persona is `profile.md`, `SOUL.md`, and `AGENTS.md` concatenated from the named directory. The
|
|
21
21
|
harness assembles them into one file in the run directory and records its path; the persona entry
|
|
22
22
|
appends that file to the system prompt on every agent start, so the repository's own `AGENTS.md`
|
|
23
23
|
keeps applying underneath it.
|
|
24
24
|
|
|
25
25
|
## What it registers
|
|
26
26
|
|
|
27
|
-
| Entry | Surface
|
|
28
|
-
| ---------------------- |
|
|
29
|
-
| `./extensions/pi` | the `/profile` command
|
|
30
|
-
| `./extensions/persona` | a `before_agent_start` hook that appends the active persona to the system prompt
|
|
27
|
+
| Entry | Surface |
|
|
28
|
+
| ---------------------- | -------------------------------------------------------------------------------------------- |
|
|
29
|
+
| `./extensions/pi` | the `/profile` command, which lists profiles, switches persona and environment, then reloads |
|
|
30
|
+
| `./extensions/persona` | a `before_agent_start` hook that appends the active persona to the system prompt |
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
DoomPi uses two entries because a detached child session needs the persona but has no transition
|
|
33
|
+
coordinator to run a switch through. DoomPi activates `./extensions/pi` in the parent and
|
|
34
|
+
`./extensions/persona` in both.
|
|
35
35
|
|
|
36
36
|
## Switching
|
|
37
37
|
|
|
@@ -40,6 +40,26 @@ A profile change is always a `pi-reload`: the extension set does not change, but
|
|
|
40
40
|
have to be dropped so every extension re-reads the environment. Active minor modes are captured
|
|
41
41
|
before the reload and restored after it.
|
|
42
42
|
|
|
43
|
+
## Configuration
|
|
44
|
+
|
|
45
|
+
Personal profiles load from `~/.pi/.doom/profiles.yaml`, then repository profiles load from
|
|
46
|
+
`.doom/profiles.yaml`. Roots discover either one persona folder or direct-child persona folders.
|
|
47
|
+
Explicit entries provide a persona path and optional string environment defaults. Resolution runs
|
|
48
|
+
from personal discovery to repository discovery, then personal explicit entries to repository
|
|
49
|
+
explicit entries. A later profile replaces an earlier profile with the same name.
|
|
50
|
+
|
|
51
|
+
Persona paths must stay inside the declaring config's `agents/` directory or a profile root from
|
|
52
|
+
that same file. Directory and persona-file symlinks cannot escape those boundaries. See the
|
|
53
|
+
shipped [profiles contract](./src/prompts/doompi-author-profile/references/profiles-contract.md) for
|
|
54
|
+
the full configuration model and verification steps.
|
|
55
|
+
|
|
56
|
+
## Help
|
|
57
|
+
|
|
58
|
+
The package registers `doompi-author-profile` with the session's `doom/help` Cordis service. Its
|
|
59
|
+
package guidance becomes visible to the AI only while the parent Help minor mode is active. The
|
|
60
|
+
registration follows the Help provider lifecycle and is withdrawn when this package or the provider
|
|
61
|
+
is disposed.
|
|
62
|
+
|
|
43
63
|
## Installation
|
|
44
64
|
|
|
45
65
|
DoomPi depends on this package and activates it as fixed host core, so a DoomPi install already has
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../telemetry/logSinkTelemetry.cjs"),t=require("../../commands/profileCommand.cjs");let n=require("@agimon-ai/doompi-extension-contracts/config"),r=require("@agimon-ai/doompi-extension-contracts/cordis-host"),i=require("@agimon-ai/doompi-extension-contracts/transition");const
|
|
1
|
+
const e=require("../telemetry/logSinkTelemetry.cjs"),t=require("../../commands/profileCommand.cjs");let n=require("@agimon-ai/doompi-extension-contracts/config"),r=require("@agimon-ai/doompi-extension-contracts/cordis-host"),i=require("@agimon-ai/doompi-extension-contracts/help"),a=require("@agimon-ai/doompi-extension-contracts/transition");const o=`@agimon-ai/doompi-profile`;async function s(t,n=e.createProfileTelemetry()){let i=await(0,r.connectDoomCordisHost)(t,o),a=i.root.plugin(c,{pi:t,telemetry:n});try{await a}catch(e){try{await a.dispose()}finally{await i.dispose()}throw e}let s;t.on(`session_shutdown`,()=>s??=(async()=>{try{await a.dispose()}finally{await i.dispose()}})())}function c(e,r){e.inject([i.DOOM_HELP_SERVICE],e=>{let t=(0,i.requireDoomHelpService)(e).register({source:o,moduleUrl:require("url").pathToFileURL(__filename).href,skills:[{name:`doompi-author-profile`,description:`Configure DoomPi profile discovery, personas, environment defaults, and precedence in profiles.yaml. Use when creating or changing personal or repository profiles. Do not use for config.yaml runtime settings, modes.yaml, or domains.yaml.`}]});return()=>t.dispose()});let s;e.inject([n.DOOM_CONFIG_SERVICE,a.DOOM_TRANSITION_SERVICE],e=>(s=e,()=>{s===e&&(s=void 0)}));let c=()=>{if(!s)throw Error(`Doom profile runtime is waiting for the session config service.`);return s};e.effect(function*(){t.registerProfileCommand(r.pi,r.telemetry,c),yield()=>void 0},o)}exports.default=s,exports.profileExtension=s;
|
|
2
2
|
//# sourceMappingURL=extension.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.cjs","names":["createProfileTelemetry","connectDoomCordisHost","DOOM_CONFIG_SERVICE","DOOM_TRANSITION_SERVICE"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { DOOM_CONFIG_SERVICE } from '@agimon-ai/doompi-extension-contracts/config';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_TRANSITION_SERVICE } from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerProfileCommand } from '../../commands/profileCommand.ts';\nimport type { ProfileTelemetry } from '../../types/telemetry.ts';\nimport { createProfileTelemetry } from '../telemetry/logSinkTelemetry.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-profile';\n\n/**\n * The package's single standard Pi factory.\n */\nexport async function profileExtension(\n pi: ExtensionAPI,\n telemetry: ProfileTelemetry = createProfileTelemetry(),\n): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(profilePlugin, { pi, telemetry });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface ProfilePluginConfig {\n readonly pi: ExtensionAPI;\n readonly telemetry: ProfileTelemetry;\n}\n\nfunction profilePlugin(cordis: Context, config: ProfilePluginConfig): void {\n let activeContext: Context | undefined;\n cordis.inject([DOOM_CONFIG_SERVICE, DOOM_TRANSITION_SERVICE], (context) => {\n activeContext = context;\n return () => {\n if (activeContext === context) activeContext = undefined;\n };\n });\n const requireRuntimeContext = (): Context => {\n if (!activeContext) throw new Error('Doom profile runtime is waiting for the session config service.');\n return activeContext;\n };\n cordis.effect(function* () {\n registerProfileCommand(config.pi, config.telemetry, requireRuntimeContext);\n yield () => undefined;\n }, PACKAGE_SOURCE);\n}\n\nexport default profileExtension;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"extension.cjs","names":["createProfileTelemetry","connectDoomCordisHost","DOOM_HELP_SERVICE","requireDoomHelpService","DOOM_CONFIG_SERVICE","DOOM_TRANSITION_SERVICE"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { DOOM_CONFIG_SERVICE } from '@agimon-ai/doompi-extension-contracts/config';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport { DOOM_TRANSITION_SERVICE } from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerProfileCommand } from '../../commands/profileCommand.ts';\nimport type { ProfileTelemetry } from '../../types/telemetry.ts';\nimport { createProfileTelemetry } from '../telemetry/logSinkTelemetry.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-profile';\n\n/**\n * The package's single standard Pi factory.\n */\nexport async function profileExtension(\n pi: ExtensionAPI,\n telemetry: ProfileTelemetry = createProfileTelemetry(),\n): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(profilePlugin, { pi, telemetry });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface ProfilePluginConfig {\n readonly pi: ExtensionAPI;\n readonly telemetry: ProfileTelemetry;\n}\n\nfunction profilePlugin(cordis: Context, config: ProfilePluginConfig): void {\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const contribution = requireDoomHelpService(helpContext).register({\n source: PACKAGE_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-author-profile',\n description:\n 'Configure DoomPi profile discovery, personas, environment defaults, and precedence in profiles.yaml. Use when creating or changing personal or repository profiles. Do not use for config.yaml runtime settings, modes.yaml, or domains.yaml.',\n },\n ],\n });\n return () => contribution.dispose();\n });\n\n let activeContext: Context | undefined;\n cordis.inject([DOOM_CONFIG_SERVICE, DOOM_TRANSITION_SERVICE], (context) => {\n activeContext = context;\n return () => {\n if (activeContext === context) activeContext = undefined;\n };\n });\n const requireRuntimeContext = (): Context => {\n if (!activeContext) throw new Error('Doom profile runtime is waiting for the session config service.');\n return activeContext;\n };\n cordis.effect(function* () {\n registerProfileCommand(config.pi, config.telemetry, requireRuntimeContext);\n yield () => undefined;\n }, PACKAGE_SOURCE);\n}\n\nexport default profileExtension;\n"],"mappings":"uVAUA,MAAM,EAAiB,4BAKvB,eAAsB,EACpB,EACA,EAA8BA,EAAAA,uBAAuB,EACtC,CACf,IAAM,EAAa,MAAA,EAAMC,EAAAA,sBAAAA,CAAsB,EAAI,CAAc,EAC3D,EAAQ,EAAW,KAAK,OAAO,EAAe,CAAE,KAAI,WAAU,CAAC,EACrE,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CACd,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACA,MAAM,CACR,CACA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF,CAOA,SAAS,EAAc,EAAiB,EAAmC,CACzE,EAAO,OAAO,CAACC,EAAAA,iBAAiB,EAAI,GAAgB,CAClD,IAAM,GAAA,EAAeC,EAAAA,uBAAAA,CAAuB,CAAW,CAAC,CAAC,SAAS,CAChE,OAAQ,EACR,UAAA,QAAA,KAAA,CAAA,CAAA,cAAA,UAAA,CAAA,CAAA,KACA,OAAQ,CACN,CACE,KAAM,wBACN,YACE,+OACJ,CACF,CACF,CAAC,EACD,UAAa,EAAa,QAAQ,CACpC,CAAC,EAED,IAAI,EACJ,EAAO,OAAO,CAACC,EAAAA,oBAAqBC,EAAAA,uBAAuB,EAAI,IAC7D,EAAgB,MACH,CACP,IAAkB,IAAS,EAAgB,IAAA,GACjD,EACD,EACD,IAAM,MAAuC,CAC3C,GAAI,CAAC,EAAe,MAAU,MAAM,iEAAiE,EACrG,OAAO,CACT,EACA,EAAO,OAAO,WAAa,CACzB,EAAA,uBAAuB,EAAO,GAAI,EAAO,UAAW,CAAqB,EACzE,SAAY,IAAA,EACd,EAAG,CAAc,CACnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;iBAesB,iBACpB,IAAI,cACJ,YAAW,mBACV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;;;iBAesB,iBACpB,IAAI,cACJ,YAAW,mBACV"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createProfileTelemetry as e}from"../telemetry/logSinkTelemetry.mjs";import{registerProfileCommand as t}from"../../commands/profileCommand.mjs";import{DOOM_CONFIG_SERVICE as n}from"@agimon-ai/doompi-extension-contracts/config";import{connectDoomCordisHost as r}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{
|
|
1
|
+
import{createProfileTelemetry as e}from"../telemetry/logSinkTelemetry.mjs";import{registerProfileCommand as t}from"../../commands/profileCommand.mjs";import{DOOM_CONFIG_SERVICE as n}from"@agimon-ai/doompi-extension-contracts/config";import{connectDoomCordisHost as r}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_HELP_SERVICE as i,requireDoomHelpService as a}from"@agimon-ai/doompi-extension-contracts/help";import{DOOM_TRANSITION_SERVICE as o}from"@agimon-ai/doompi-extension-contracts/transition";const s=`@agimon-ai/doompi-profile`;async function c(t,n=e()){let i=await r(t,s),a=i.root.plugin(l,{pi:t,telemetry:n});try{await a}catch(e){try{await a.dispose()}finally{await i.dispose()}throw e}let o;t.on(`session_shutdown`,()=>o??=(async()=>{try{await a.dispose()}finally{await i.dispose()}})())}function l(e,r){e.inject([i],e=>{let t=a(e).register({source:s,moduleUrl:import.meta.url,skills:[{name:`doompi-author-profile`,description:`Configure DoomPi profile discovery, personas, environment defaults, and precedence in profiles.yaml. Use when creating or changing personal or repository profiles. Do not use for config.yaml runtime settings, modes.yaml, or domains.yaml.`}]});return()=>t.dispose()});let c;e.inject([n,o],e=>(c=e,()=>{c===e&&(c=void 0)}));let l=()=>{if(!c)throw Error(`Doom profile runtime is waiting for the session config service.`);return c};e.effect(function*(){t(r.pi,r.telemetry,l),yield()=>void 0},s)}export{c as default,c as profileExtension};
|
|
2
2
|
//# sourceMappingURL=extension.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { DOOM_CONFIG_SERVICE } from '@agimon-ai/doompi-extension-contracts/config';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_TRANSITION_SERVICE } from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerProfileCommand } from '../../commands/profileCommand.ts';\nimport type { ProfileTelemetry } from '../../types/telemetry.ts';\nimport { createProfileTelemetry } from '../telemetry/logSinkTelemetry.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-profile';\n\n/**\n * The package's single standard Pi factory.\n */\nexport async function profileExtension(\n pi: ExtensionAPI,\n telemetry: ProfileTelemetry = createProfileTelemetry(),\n): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(profilePlugin, { pi, telemetry });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface ProfilePluginConfig {\n readonly pi: ExtensionAPI;\n readonly telemetry: ProfileTelemetry;\n}\n\nfunction profilePlugin(cordis: Context, config: ProfilePluginConfig): void {\n let activeContext: Context | undefined;\n cordis.inject([DOOM_CONFIG_SERVICE, DOOM_TRANSITION_SERVICE], (context) => {\n activeContext = context;\n return () => {\n if (activeContext === context) activeContext = undefined;\n };\n });\n const requireRuntimeContext = (): Context => {\n if (!activeContext) throw new Error('Doom profile runtime is waiting for the session config service.');\n return activeContext;\n };\n cordis.effect(function* () {\n registerProfileCommand(config.pi, config.telemetry, requireRuntimeContext);\n yield () => undefined;\n }, PACKAGE_SOURCE);\n}\n\nexport default profileExtension;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { DOOM_CONFIG_SERVICE } from '@agimon-ai/doompi-extension-contracts/config';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport { DOOM_TRANSITION_SERVICE } from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { registerProfileCommand } from '../../commands/profileCommand.ts';\nimport type { ProfileTelemetry } from '../../types/telemetry.ts';\nimport { createProfileTelemetry } from '../telemetry/logSinkTelemetry.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-profile';\n\n/**\n * The package's single standard Pi factory.\n */\nexport async function profileExtension(\n pi: ExtensionAPI,\n telemetry: ProfileTelemetry = createProfileTelemetry(),\n): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(profilePlugin, { pi, telemetry });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface ProfilePluginConfig {\n readonly pi: ExtensionAPI;\n readonly telemetry: ProfileTelemetry;\n}\n\nfunction profilePlugin(cordis: Context, config: ProfilePluginConfig): void {\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const contribution = requireDoomHelpService(helpContext).register({\n source: PACKAGE_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-author-profile',\n description:\n 'Configure DoomPi profile discovery, personas, environment defaults, and precedence in profiles.yaml. Use when creating or changing personal or repository profiles. Do not use for config.yaml runtime settings, modes.yaml, or domains.yaml.',\n },\n ],\n });\n return () => contribution.dispose();\n });\n\n let activeContext: Context | undefined;\n cordis.inject([DOOM_CONFIG_SERVICE, DOOM_TRANSITION_SERVICE], (context) => {\n activeContext = context;\n return () => {\n if (activeContext === context) activeContext = undefined;\n };\n });\n const requireRuntimeContext = (): Context => {\n if (!activeContext) throw new Error('Doom profile runtime is waiting for the session config service.');\n return activeContext;\n };\n cordis.effect(function* () {\n registerProfileCommand(config.pi, config.telemetry, requireRuntimeContext);\n yield () => undefined;\n }, PACKAGE_SOURCE);\n}\n\nexport default profileExtension;\n"],"mappings":"ygBAUA,MAAM,EAAiB,4BAKvB,eAAsB,EACpB,EACA,EAA8B,EAAuB,EACtC,CACf,IAAM,EAAa,MAAM,EAAsB,EAAI,CAAc,EAC3D,EAAQ,EAAW,KAAK,OAAO,EAAe,CAAE,KAAI,WAAU,CAAC,EACrE,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CACd,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACA,MAAM,CACR,CACA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF,CAOA,SAAS,EAAc,EAAiB,EAAmC,CACzE,EAAO,OAAO,CAAC,CAAiB,EAAI,GAAgB,CAClD,IAAM,EAAe,EAAuB,CAAW,CAAC,CAAC,SAAS,CAChE,OAAQ,EACR,UAAW,YAAY,IACvB,OAAQ,CACN,CACE,KAAM,wBACN,YACE,+OACJ,CACF,CACF,CAAC,EACD,UAAa,EAAa,QAAQ,CACpC,CAAC,EAED,IAAI,EACJ,EAAO,OAAO,CAAC,EAAqB,CAAuB,EAAI,IAC7D,EAAgB,MACH,CACP,IAAkB,IAAS,EAAgB,IAAA,GACjD,EACD,EACD,IAAM,MAAuC,CAC3C,GAAI,CAAC,EAAe,MAAU,MAAM,iEAAiE,EACrG,OAAO,CACT,EACA,EAAO,OAAO,WAAa,CACzB,EAAuB,EAAO,GAAI,EAAO,UAAW,CAAqB,EACzE,SAAY,IAAA,EACd,EAAG,CAAc,CACnB"}
|
package/llms.txt
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
# Doom Pi Profile
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Package-owned guidance for DoomPi profile discovery, personas, environment defaults, and precedence.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## How to author
|
|
6
6
|
|
|
7
|
-
- [
|
|
7
|
+
- [Author DoomPi profiles](./src/prompts/doompi-author-profile/SKILL.md): Configure personal and repository profiles.
|
|
8
|
+
- [Profiles authoring contract](./src/prompts/doompi-author-profile/references/profiles-contract.md): File locations, discovery, precedence, path safety, environment defaults, and verification.
|
|
9
|
+
|
|
10
|
+
## Package reference
|
|
11
|
+
|
|
12
|
+
- [Package README](./README.md): Profile behavior, activation, and public package entries.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/doompi-profile",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.7",
|
|
4
4
|
"description": "Persona and environment profile switching for DoomPi sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-persona",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"dist",
|
|
22
22
|
"llms.txt",
|
|
23
23
|
"README.md",
|
|
24
|
+
"src/prompts",
|
|
24
25
|
"LICENSE",
|
|
25
26
|
"package.json"
|
|
26
27
|
],
|
|
@@ -51,13 +52,12 @@
|
|
|
51
52
|
},
|
|
52
53
|
"dependencies": {
|
|
53
54
|
"@deepseek-ai/cordis": "4.0.1",
|
|
54
|
-
"@agimon-ai/doompi-config": "0.0.1-alpha.
|
|
55
|
-
"@agimon-ai/doompi-
|
|
56
|
-
"@agimon-ai/doompi-
|
|
57
|
-
"@agimon-ai/doompi-
|
|
55
|
+
"@agimon-ai/doompi-config": "0.0.1-alpha.29",
|
|
56
|
+
"@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.29",
|
|
57
|
+
"@agimon-ai/doompi-telemetry": "0.0.1-alpha.29",
|
|
58
|
+
"@agimon-ai/doompi-ui": "0.0.1-alpha.29"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
60
|
-
"@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.1-alpha.26",
|
|
61
61
|
"@deepseek-ai/cordis": "4.0.1",
|
|
62
62
|
"@earendil-works/pi-coding-agent": "0.84.2",
|
|
63
63
|
"@earendil-works/pi-tui": "0.84.2",
|
|
@@ -65,7 +65,8 @@
|
|
|
65
65
|
"@vitest/coverage-v8": "4.1.11",
|
|
66
66
|
"tsdown": "0.22.14",
|
|
67
67
|
"typescript": "7.0.2",
|
|
68
|
-
"vitest": "4.1.11"
|
|
68
|
+
"vitest": "4.1.11",
|
|
69
|
+
"@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.1-alpha.27"
|
|
69
70
|
},
|
|
70
71
|
"peerDependencies": {
|
|
71
72
|
"@earendil-works/pi-coding-agent": "0.84.2",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: doompi-author-profile
|
|
3
|
+
description: Configure DoomPi profile discovery, personas, environment defaults, and precedence in profiles.yaml. Use when creating or changing personal or repository profiles. Do not use for config.yaml runtime settings, modes.yaml, or domains.yaml.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Author DoomPi profiles
|
|
7
|
+
|
|
8
|
+
Configure a profile as one persona plus optional environment defaults.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. Read both `~/.pi/.doom/profiles.yaml` and the repository's `.doom/profiles.yaml` when they exist.
|
|
13
|
+
2. Use `profiles.roots` for one-level persona discovery. Use `profiles.entries` when a profile needs an explicit persona path or environment defaults.
|
|
14
|
+
3. Resolve relative roots and persona paths against the file that declares them. Keep an explicit persona inside that file's `agents/` directory or one of its configured roots.
|
|
15
|
+
4. Put instructions in `profile.md`, `SOUL.md`, or `AGENTS.md`. DoomPi concatenates non-empty files in that order.
|
|
16
|
+
5. Keep every `env` value a string. Treat it as a default because an already exported value wins.
|
|
17
|
+
6. Preserve the precedence rules. Explicit entries override discoveries, and repository entries override personal entries at the same precedence level.
|
|
18
|
+
7. Verify the selection with `doompi --profile <name> --explain`, then smoke-test `/profile` when changing live switching behavior.
|
|
19
|
+
|
|
20
|
+
Read [references/profiles-contract.md](references/profiles-contract.md) before changing discovery, precedence, path handling, or profile application.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# DoomPi profiles authoring contract
|
|
2
|
+
|
|
3
|
+
## Sources and shape
|
|
4
|
+
|
|
5
|
+
DoomPi reads profile declarations in this order:
|
|
6
|
+
|
|
7
|
+
1. `~/.pi/.doom/profiles.yaml`
|
|
8
|
+
2. `<repoRoot>/.doom/profiles.yaml`
|
|
9
|
+
|
|
10
|
+
The current catalog shape is:
|
|
11
|
+
|
|
12
|
+
```yaml
|
|
13
|
+
profiles:
|
|
14
|
+
roots: [agents/acme]
|
|
15
|
+
entries:
|
|
16
|
+
writer:
|
|
17
|
+
persona: agents/special/writer
|
|
18
|
+
env:
|
|
19
|
+
BRAND: acme
|
|
20
|
+
TONE: concise
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The document may contain only the `profiles` mapping. In catalog form, `profiles` may contain only
|
|
24
|
+
`roots` and `entries`. DoomPi still accepts the earlier flat form, where profile names appear
|
|
25
|
+
directly below `profiles`, but new configuration should use catalog form.
|
|
26
|
+
|
|
27
|
+
Every relative root or persona path resolves against the file that declares it. Repository paths
|
|
28
|
+
resolve from the repository root. Personal paths resolve from `~/.pi/.doom`.
|
|
29
|
+
|
|
30
|
+
## Root discovery
|
|
31
|
+
|
|
32
|
+
Each `profiles.roots` value must resolve to an existing directory.
|
|
33
|
+
|
|
34
|
+
- If the root directly contains `profile.md`, `SOUL.md`, or `AGENTS.md`, the root is one profile.
|
|
35
|
+
Its directory name is the profile name, and its children are not scanned.
|
|
36
|
+
- Otherwise, DoomPi inspects only the root's direct-child directories. A child becomes a profile
|
|
37
|
+
when it directly contains at least one persona file.
|
|
38
|
+
- Discovery does not recurse. Add another root or an explicit entry for a deeper persona.
|
|
39
|
+
- A discovered profile has an empty environment mapping.
|
|
40
|
+
- Unreadable candidates and candidates whose real path or persona files escape the configured root
|
|
41
|
+
are ignored. An invalid configured root itself is an error.
|
|
42
|
+
|
|
43
|
+
## Explicit entries and path confinement
|
|
44
|
+
|
|
45
|
+
An explicit entry may contain only `persona` and `env`. `persona` is required, must be a non-empty
|
|
46
|
+
relative path, and must resolve to a directory containing readable persona content.
|
|
47
|
+
|
|
48
|
+
The persona must remain inside either:
|
|
49
|
+
|
|
50
|
+
- the `agents/` directory beside the declaring repository root or personal `.doom` directory, or
|
|
51
|
+
- one of the `profiles.roots` directories declared in that same file.
|
|
52
|
+
|
|
53
|
+
DoomPi checks both the lexical path and the real filesystem path. A persona-directory symlink cannot
|
|
54
|
+
escape an allowed root. Each resolved persona file must also remain inside the real persona
|
|
55
|
+
directory, so a file symlink cannot import instructions from outside it. Invalid explicit entries
|
|
56
|
+
fail loading instead of being skipped.
|
|
57
|
+
|
|
58
|
+
Persona content is assembled from non-empty files in this order:
|
|
59
|
+
|
|
60
|
+
1. `profile.md`
|
|
61
|
+
2. `SOUL.md`
|
|
62
|
+
3. `AGENTS.md`
|
|
63
|
+
|
|
64
|
+
## Precedence
|
|
65
|
+
|
|
66
|
+
DoomPi resolves names in four passes, from lowest to highest precedence:
|
|
67
|
+
|
|
68
|
+
1. Personal root discoveries
|
|
69
|
+
2. Repository root discoveries
|
|
70
|
+
3. Personal explicit entries
|
|
71
|
+
4. Repository explicit entries
|
|
72
|
+
|
|
73
|
+
A later profile replaces an earlier profile with the same name. This means any explicit entry
|
|
74
|
+
overrides discovery, including a personal explicit entry replacing a repository discovery. A
|
|
75
|
+
repository explicit entry wins over a personal explicit entry. Unrelated names from all sources
|
|
76
|
+
remain available, and the final list is sorted by profile name.
|
|
77
|
+
|
|
78
|
+
## Environment defaults and activation
|
|
79
|
+
|
|
80
|
+
Every `env` key maps to a string. Applying a profile writes only variables that are not already
|
|
81
|
+
exported by the caller. When switching profiles, DoomPi removes a value contributed by the previous
|
|
82
|
+
profile only if that value has not since changed, then applies the next profile's defaults.
|
|
83
|
+
|
|
84
|
+
The `/profile` command resolves the named profile and executes the change through the session
|
|
85
|
+
transition coordinator. A profile change uses Pi reload so extensions re-read the environment.
|
|
86
|
+
DoomPi assembles the persona into a private run-directory file, and the persona Pi entry appends
|
|
87
|
+
that content to the system prompt after reload.
|
|
88
|
+
|
|
89
|
+
## Verification
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
pnpm nx test @agimon-ai/doompi-config
|
|
93
|
+
pnpm nx typecheck @agimon-ai/doompi-config
|
|
94
|
+
pnpm nx test @agimon-ai/doompi-profile
|
|
95
|
+
pnpm nx typecheck @agimon-ai/doompi-profile
|
|
96
|
+
pnpm --filter @agimon-ai/doompi exec doompi --profile writer --explain
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Use an actual parent session to smoke-test `/profile` when changing transition, environment, or
|
|
100
|
+
persona application behavior.
|