@ai-outfitter/outfitter 0.11.0 → 1.0.2
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/.outfitter/skills/outfitter/SKILL.md +67 -37
- package/README.md +63 -35
- package/code/enterprise/cli/privateCatalogSettings.cjs +2 -2
- package/code/enterprise/pi-extension/privateCatalogOnboarding.js +5 -8
- package/code/enterprise/shared/privateCatalogPolicy.cjs +5 -5
- package/code/pi-extension/src/outfitter-extension.js +353 -553
- package/code/pi-extension/src/outfitter-runtime-extension.js +160 -0
- package/dist/agents/AgentLaunch.d.ts +9 -1
- package/dist/agents/AgentLaunch.js +19 -0
- package/dist/agents/AgentLaunch.js.map +1 -1
- package/dist/agents/PiCredentialPersistence.d.ts +6 -0
- package/dist/agents/PiCredentialPersistence.js +33 -0
- package/dist/agents/PiCredentialPersistence.js.map +1 -0
- package/dist/cli/OutfitterCli.js +10 -18
- package/dist/cli/OutfitterCli.js.map +1 -1
- package/dist/cli/commands/CommandObject.d.ts +0 -5
- package/dist/cli/commands/CommandObject.js +1 -4
- package/dist/cli/commands/CommandObject.js.map +1 -1
- package/dist/cli/commands/DumpCommand.d.ts +19 -0
- package/dist/cli/commands/DumpCommand.js +54 -0
- package/dist/cli/commands/DumpCommand.js.map +1 -0
- package/dist/cli/commands/ListCommand.d.ts +17 -0
- package/dist/cli/commands/ListCommand.js +77 -0
- package/dist/cli/commands/ListCommand.js.map +1 -0
- package/dist/cli/commands/PiRuntimeLaunch.d.ts +8 -0
- package/dist/cli/commands/PiRuntimeLaunch.js +47 -0
- package/dist/cli/commands/PiRuntimeLaunch.js.map +1 -0
- package/dist/cli/commands/ProcessDefaults.d.ts +2 -0
- package/dist/cli/commands/ProcessDefaults.js +5 -0
- package/dist/cli/commands/ProcessDefaults.js.map +1 -0
- package/dist/cli/commands/RunAgentCommand.d.ts +46 -0
- package/dist/cli/commands/RunAgentCommand.js +176 -0
- package/dist/cli/commands/RunAgentCommand.js.map +1 -0
- package/dist/cli/commands/SetupCommand.d.ts +38 -6
- package/dist/cli/commands/SetupCommand.js +194 -232
- package/dist/cli/commands/SetupCommand.js.map +1 -1
- package/dist/cli/commands/ValidateCommand.d.ts +20 -0
- package/dist/cli/commands/ValidateCommand.js +54 -0
- package/dist/cli/commands/ValidateCommand.js.map +1 -0
- package/dist/composer/Composer.d.ts +11 -0
- package/dist/composer/Composer.js +72 -0
- package/dist/composer/Composer.js.map +1 -0
- package/dist/composer/Composition.d.ts +33 -0
- package/dist/composer/Composition.js +2 -0
- package/dist/composer/Composition.js.map +1 -0
- package/dist/dump/Containment.d.ts +8 -0
- package/dist/dump/Containment.js +22 -0
- package/dist/dump/Containment.js.map +1 -0
- package/dist/dump/Dump.d.ts +8 -0
- package/dist/dump/Dump.js +182 -0
- package/dist/dump/Dump.js.map +1 -0
- package/dist/extensions/PiExtensionCache.d.ts +30 -0
- package/dist/extensions/PiExtensionCache.js +92 -0
- package/dist/extensions/PiExtensionCache.js.map +1 -0
- package/dist/fs/TypeConflict.d.ts +6 -0
- package/dist/fs/TypeConflict.js +21 -0
- package/dist/fs/TypeConflict.js.map +1 -0
- package/dist/paths/OutfitterCache.d.ts +6 -0
- package/dist/paths/OutfitterCache.js +17 -0
- package/dist/paths/OutfitterCache.js.map +1 -0
- package/dist/projection/Materialize.d.ts +24 -0
- package/dist/projection/Materialize.js +83 -0
- package/dist/projection/Materialize.js.map +1 -0
- package/dist/projection/ProjectHarness.d.ts +5 -0
- package/dist/projection/ProjectHarness.js +77 -0
- package/dist/projection/ProjectHarness.js.map +1 -0
- package/dist/projection/Projection.d.ts +23 -0
- package/dist/projection/Projection.js +2 -0
- package/dist/projection/Projection.js.map +1 -0
- package/dist/resolver/AgentDefinition.d.ts +30 -0
- package/dist/resolver/AgentDefinition.js +123 -0
- package/dist/resolver/AgentDefinition.js.map +1 -0
- package/dist/resolver/Layer.d.ts +12 -0
- package/dist/resolver/Layer.js +30 -0
- package/dist/resolver/Layer.js.map +1 -0
- package/dist/resolver/Resolver.d.ts +3 -0
- package/dist/resolver/Resolver.js +163 -0
- package/dist/resolver/Resolver.js.map +1 -0
- package/dist/resolver/ResolverContext.d.ts +15 -0
- package/dist/resolver/ResolverContext.js +11 -0
- package/dist/resolver/ResolverContext.js.map +1 -0
- package/dist/resolver/ResolverValidation.d.ts +11 -0
- package/dist/resolver/ResolverValidation.js +112 -0
- package/dist/resolver/ResolverValidation.js.map +1 -0
- package/dist/resolver/Resource.d.ts +88 -0
- package/dist/resolver/Resource.js +34 -0
- package/dist/resolver/Resource.js.map +1 -0
- package/dist/schemas/agent.schema.json +48 -0
- package/dist/schemas/settings.schema.json +32 -9
- package/dist/settings/Settings.d.ts +34 -5
- package/dist/settings/Settings.js +3 -1
- package/dist/settings/Settings.js.map +1 -1
- package/dist/settings/SettingsLoader.d.ts +1 -1
- package/dist/settings/SettingsLoader.js +23 -22
- package/dist/settings/SettingsLoader.js.map +1 -1
- package/dist/settings/SettingsMerger.js +12 -10
- package/dist/settings/SettingsMerger.js.map +1 -1
- package/dist/setup/DefaultCatalog.d.ts +20 -0
- package/dist/setup/DefaultCatalog.js +89 -0
- package/dist/setup/DefaultCatalog.js.map +1 -0
- package/dist/setup/Setup.d.ts +43 -0
- package/dist/setup/Setup.js +261 -0
- package/dist/setup/Setup.js.map +1 -0
- package/dist/skills/SkillDocument.d.ts +6 -1
- package/dist/skills/SkillDocument.js.map +1 -1
- package/dist/sources/SourceCache.d.ts +19 -0
- package/dist/{profiles/ProfileCache.js → sources/SourceCache.js} +22 -18
- package/dist/sources/SourceCache.js.map +1 -0
- package/dist/validation/SchemaValidator.d.ts +1 -1
- package/dist/validation/SchemaValidator.js +4 -13
- package/dist/validation/SchemaValidator.js.map +1 -1
- package/docs/architecture/state_writeback_strategy.md +54 -122
- package/docs/documentation/README.md +33 -12
- package/docs/documentation/actions.md +35 -52
- package/docs/documentation/agents.md +109 -0
- package/docs/documentation/best-practices.md +25 -63
- package/docs/documentation/catalogs.md +126 -0
- package/docs/documentation/cli.md +39 -41
- package/docs/documentation/concepts.md +66 -23
- package/docs/documentation/dump-and-bake.md +30 -0
- package/docs/documentation/first-time-cli-agent-users.md +8 -8
- package/docs/documentation/getting-started.md +28 -8
- package/docs/documentation/hooks.md +20 -0
- package/docs/documentation/iterating-on-profiles.md +56 -70
- package/docs/documentation/local-development.md +84 -0
- package/docs/documentation/migration.md +39 -0
- package/docs/documentation/personas.md +41 -0
- package/docs/documentation/porting-claude.md +54 -0
- package/docs/documentation/profiles.md +16 -169
- package/docs/documentation/settings.md +61 -0
- package/docs/documentation/skills.md +93 -334
- package/docs/documentation/state.md +24 -62
- package/docs/documentation/subagents.md +37 -0
- package/docs/documentation/support-matrix.md +40 -35
- package/docs/documentation/switching-to-outfitter.md +75 -81
- package/docs/documentation/tasks.md +13 -0
- package/docs/documentation/usecases/engineering.md +67 -84
- package/docs/documentation/usecases/organization-profile-catalog.md +83 -111
- package/docs/documentation/usecases/persona-reviews.md +133 -139
- package/docs/philosophy.md +2 -2
- package/package.json +3 -3
- package/src/schemas/agent.schema.json +48 -0
- package/src/schemas/settings.schema.json +32 -9
- package/dist/agents/AdapterProfileControls.d.ts +0 -21
- package/dist/agents/AdapterProfileControls.js +0 -76
- package/dist/agents/AdapterProfileControls.js.map +0 -1
- package/dist/agents/AdapterStatePaths.d.ts +0 -12
- package/dist/agents/AdapterStatePaths.js +0 -46
- package/dist/agents/AdapterStatePaths.js.map +0 -1
- package/dist/agents/AgentAdapter.d.ts +0 -44
- package/dist/agents/AgentAdapter.js +0 -2
- package/dist/agents/AgentAdapter.js.map +0 -1
- package/dist/agents/AgentRegistry.d.ts +0 -6
- package/dist/agents/AgentRegistry.js +0 -17
- package/dist/agents/AgentRegistry.js.map +0 -1
- package/dist/agents/LaunchResources.d.ts +0 -17
- package/dist/agents/LaunchResources.js +0 -61
- package/dist/agents/LaunchResources.js.map +0 -1
- package/dist/agents/OutfitterSkill.d.ts +0 -11
- package/dist/agents/OutfitterSkill.js +0 -128
- package/dist/agents/OutfitterSkill.js.map +0 -1
- package/dist/agents/ResourceIdentity.d.ts +0 -2
- package/dist/agents/ResourceIdentity.js +0 -51
- package/dist/agents/ResourceIdentity.js.map +0 -1
- package/dist/agents/claude/ClaudeAdapter.d.ts +0 -2
- package/dist/agents/claude/ClaudeAdapter.js +0 -148
- package/dist/agents/claude/ClaudeAdapter.js.map +0 -1
- package/dist/agents/claude/ClaudeCompositeProfileWriter.d.ts +0 -5
- package/dist/agents/claude/ClaudeCompositeProfileWriter.js +0 -7
- package/dist/agents/claude/ClaudeCompositeProfileWriter.js.map +0 -1
- package/dist/agents/pi/PiAdapter.d.ts +0 -2
- package/dist/agents/pi/PiAdapter.js +0 -363
- package/dist/agents/pi/PiAdapter.js.map +0 -1
- package/dist/agents/pi/PiArgs.d.ts +0 -2
- package/dist/agents/pi/PiArgs.js +0 -15
- package/dist/agents/pi/PiArgs.js.map +0 -1
- package/dist/agents/pi/PiCompositeProfileWriter.d.ts +0 -5
- package/dist/agents/pi/PiCompositeProfileWriter.js +0 -7
- package/dist/agents/pi/PiCompositeProfileWriter.js.map +0 -1
- package/dist/agents/pi/PiExtensionCache.d.ts +0 -12
- package/dist/agents/pi/PiExtensionCache.js +0 -195
- package/dist/agents/pi/PiExtensionCache.js.map +0 -1
- package/dist/agents/pi/PiMcpConfig.d.ts +0 -2
- package/dist/agents/pi/PiMcpConfig.js +0 -114
- package/dist/agents/pi/PiMcpConfig.js.map +0 -1
- package/dist/agents/pi/PiSettingsMergePolicy.d.ts +0 -17
- package/dist/agents/pi/PiSettingsMergePolicy.js +0 -59
- package/dist/agents/pi/PiSettingsMergePolicy.js.map +0 -1
- package/dist/agents/pi/PiSkillSources.d.ts +0 -8
- package/dist/agents/pi/PiSkillSources.js +0 -73
- package/dist/agents/pi/PiSkillSources.js.map +0 -1
- package/dist/cli/commands/FirstRunWelcomeProfile.d.ts +0 -11
- package/dist/cli/commands/FirstRunWelcomeProfile.js +0 -110
- package/dist/cli/commands/FirstRunWelcomeProfile.js.map +0 -1
- package/dist/cli/commands/PiLoginLaunch.d.ts +0 -22
- package/dist/cli/commands/PiLoginLaunch.js +0 -170
- package/dist/cli/commands/PiLoginLaunch.js.map +0 -1
- package/dist/cli/commands/RunCommand.d.ts +0 -36
- package/dist/cli/commands/RunCommand.js +0 -345
- package/dist/cli/commands/RunCommand.js.map +0 -1
- package/dist/cli/commands/SyncCommand.d.ts +0 -46
- package/dist/cli/commands/SyncCommand.js +0 -244
- package/dist/cli/commands/SyncCommand.js.map +0 -1
- package/dist/cli/commands/WelcomeCommand.d.ts +0 -56
- package/dist/cli/commands/WelcomeCommand.js +0 -224
- package/dist/cli/commands/WelcomeCommand.js.map +0 -1
- package/dist/cli/commands/assets/outfitter-ascii.txt +0 -5
- package/dist/cli/commands/profile/Command.d.ts +0 -7
- package/dist/cli/commands/profile/Command.js +0 -24
- package/dist/cli/commands/profile/Command.js.map +0 -1
- package/dist/cli/commands/profile/CreateCommand.d.ts +0 -19
- package/dist/cli/commands/profile/CreateCommand.js +0 -115
- package/dist/cli/commands/profile/CreateCommand.js.map +0 -1
- package/dist/cli/commands/profile/LintCommand.d.ts +0 -19
- package/dist/cli/commands/profile/LintCommand.js +0 -155
- package/dist/cli/commands/profile/LintCommand.js.map +0 -1
- package/dist/cli/commands/profile/ListCommand.d.ts +0 -19
- package/dist/cli/commands/profile/ListCommand.js +0 -91
- package/dist/cli/commands/profile/ListCommand.js.map +0 -1
- package/dist/cli/commands/profile/Shared.d.ts +0 -9
- package/dist/cli/commands/profile/Shared.js +0 -10
- package/dist/cli/commands/profile/Shared.js.map +0 -1
- package/dist/cli/commands/run/RunFirstRunOnboarding.d.ts +0 -7
- package/dist/cli/commands/run/RunFirstRunOnboarding.js +0 -52
- package/dist/cli/commands/run/RunFirstRunOnboarding.js.map +0 -1
- package/dist/cli/commands/run/RunLaunchSummary.d.ts +0 -2
- package/dist/cli/commands/run/RunLaunchSummary.js +0 -35
- package/dist/cli/commands/run/RunLaunchSummary.js.map +0 -1
- package/dist/cli/commands/run/RunProfileResolution.d.ts +0 -39
- package/dist/cli/commands/run/RunProfileResolution.js +0 -128
- package/dist/cli/commands/run/RunProfileResolution.js.map +0 -1
- package/dist/cli/commands/run/RunStateWritePrompt.d.ts +0 -2
- package/dist/cli/commands/run/RunStateWritePrompt.js +0 -29
- package/dist/cli/commands/run/RunStateWritePrompt.js.map +0 -1
- package/dist/cli/commands/setup/SetupPrompts.d.ts +0 -14
- package/dist/cli/commands/setup/SetupPrompts.js +0 -296
- package/dist/cli/commands/setup/SetupPrompts.js.map +0 -1
- package/dist/cli/commands/setup/SetupSourceImport.d.ts +0 -5
- package/dist/cli/commands/setup/SetupSourceImport.js +0 -177
- package/dist/cli/commands/setup/SetupSourceImport.js.map +0 -1
- package/dist/cli/commands/setup/SetupSourceLaunch.d.ts +0 -4
- package/dist/cli/commands/setup/SetupSourceLaunch.js +0 -65
- package/dist/cli/commands/setup/SetupSourceLaunch.js.map +0 -1
- package/dist/cli/commands/setup/SetupStarterSource.d.ts +0 -21
- package/dist/cli/commands/setup/SetupStarterSource.js +0 -133
- package/dist/cli/commands/setup/SetupStarterSource.js.map +0 -1
- package/dist/cli/commands/setup/SetupTypes.d.ts +0 -91
- package/dist/cli/commands/setup/SetupTypes.js +0 -26
- package/dist/cli/commands/setup/SetupTypes.js.map +0 -1
- package/dist/compositeProfile/CompositeProfile.d.ts +0 -8
- package/dist/compositeProfile/CompositeProfile.js +0 -6
- package/dist/compositeProfile/CompositeProfile.js.map +0 -1
- package/dist/compositeProfile/CompositeProfileAssembler.d.ts +0 -12
- package/dist/compositeProfile/CompositeProfileAssembler.js +0 -32
- package/dist/compositeProfile/CompositeProfileAssembler.js.map +0 -1
- package/dist/compositeProfile/CompositeProfileCleanup.d.ts +0 -9
- package/dist/compositeProfile/CompositeProfileCleanup.js +0 -87
- package/dist/compositeProfile/CompositeProfileCleanup.js.map +0 -1
- package/dist/compositeProfile/CompositeProfileFile.d.ts +0 -16
- package/dist/compositeProfile/CompositeProfileFile.js +0 -16
- package/dist/compositeProfile/CompositeProfileFile.js.map +0 -1
- package/dist/compositeProfile/CompositeProfileTemplate.d.ts +0 -15
- package/dist/compositeProfile/CompositeProfileTemplate.js +0 -65
- package/dist/compositeProfile/CompositeProfileTemplate.js.map +0 -1
- package/dist/compositeProfile/CompositeProfileWatcher.d.ts +0 -18
- package/dist/compositeProfile/CompositeProfileWatcher.js +0 -46
- package/dist/compositeProfile/CompositeProfileWatcher.js.map +0 -1
- package/dist/compositeProfile/StatePersistence.d.ts +0 -39
- package/dist/compositeProfile/StatePersistence.js +0 -249
- package/dist/compositeProfile/StatePersistence.js.map +0 -1
- package/dist/fs/SafeSymlink.d.ts +0 -13
- package/dist/fs/SafeSymlink.js +0 -50
- package/dist/fs/SafeSymlink.js.map +0 -1
- package/dist/profiles/Profile.d.ts +0 -60
- package/dist/profiles/Profile.js +0 -7
- package/dist/profiles/Profile.js.map +0 -1
- package/dist/profiles/ProfileCache.d.ts +0 -8
- package/dist/profiles/ProfileCache.js.map +0 -1
- package/dist/profiles/ProfileLoader.d.ts +0 -28
- package/dist/profiles/ProfileLoader.js +0 -299
- package/dist/profiles/ProfileLoader.js.map +0 -1
- package/dist/profiles/ProfileMerger.d.ts +0 -19
- package/dist/profiles/ProfileMerger.js +0 -112
- package/dist/profiles/ProfileMerger.js.map +0 -1
- package/dist/profiles/ProfileSource.d.ts +0 -35
- package/dist/profiles/ProfileSource.js +0 -13
- package/dist/profiles/ProfileSource.js.map +0 -1
- package/dist/profiles/PromptIncludes.d.ts +0 -32
- package/dist/profiles/PromptIncludes.js +0 -147
- package/dist/profiles/PromptIncludes.js.map +0 -1
- package/dist/prompts/SystemPromptExport.d.ts +0 -16
- package/dist/prompts/SystemPromptExport.js +0 -81
- package/dist/prompts/SystemPromptExport.js.map +0 -1
- package/dist/schemas/profile-source.schema.json +0 -29
- package/dist/schemas/profile.schema.json +0 -200
- package/dist/skills/ProfileSkillResolution.d.ts +0 -21
- package/dist/skills/ProfileSkillResolution.js +0 -88
- package/dist/skills/ProfileSkillResolution.js.map +0 -1
- package/dist/skills/SkillCatalog.d.ts +0 -41
- package/dist/skills/SkillCatalog.js +0 -119
- package/dist/skills/SkillCatalog.js.map +0 -1
- package/dist/skills/SkillResolution.d.ts +0 -34
- package/dist/skills/SkillResolution.js +0 -369
- package/dist/skills/SkillResolution.js.map +0 -1
- package/docs/documentation/profile-repository.md +0 -179
- package/src/schemas/SchemaDocument.ts +0 -20
- package/src/schemas/profile-source.schema.json +0 -29
- package/src/schemas/profile.schema.json +0 -200
|
@@ -1,22 +1,13 @@
|
|
|
1
|
-
// Validates parsed Outfitter YAML documents against bundled JSON Schemas.
|
|
1
|
+
// Validates parsed Outfitter YAML/JSON documents against bundled JSON Schemas.
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { Ajv2020 } from 'ajv/dist/2020.js';
|
|
4
4
|
const readSchema = (schemaFileName) => JSON.parse(readFileSync(new URL(`../schemas/${schemaFileName}`, import.meta.url), 'utf8'));
|
|
5
5
|
const settingsSchema = readSchema('settings.schema.json');
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const createAjv = () => {
|
|
9
|
-
const ajv = new Ajv2020({ allErrors: true });
|
|
10
|
-
ajv.addSchema(profileSourceSchema, 'profile-source.schema.json');
|
|
11
|
-
ajv.addSchema(profileSchema, 'profile.schema.json');
|
|
12
|
-
ajv.addSchema(settingsSchema, 'settings.schema.json');
|
|
13
|
-
return ajv;
|
|
14
|
-
};
|
|
15
|
-
const ajv = createAjv();
|
|
6
|
+
const agentSchema = readSchema('agent.schema.json');
|
|
7
|
+
const ajv = new Ajv2020({ allErrors: true });
|
|
16
8
|
const validators = {
|
|
17
9
|
settings: ajv.compile(settingsSchema),
|
|
18
|
-
|
|
19
|
-
'profile-source': ajv.compile(profileSourceSchema),
|
|
10
|
+
agent: ajv.compile(agentSchema),
|
|
20
11
|
};
|
|
21
12
|
export const createValidationResult = (issues) => ({
|
|
22
13
|
valid: issues.length === 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SchemaValidator.js","sourceRoot":"","sources":["../../src/validation/SchemaValidator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"SchemaValidator.js","sourceRoot":"","sources":["../../src/validation/SchemaValidator.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAc3C,MAAM,UAAU,GAAG,CAAC,cAAsB,EAAW,EAAE,CACrD,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,cAAc,cAAc,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAE7F,MAAM,cAAc,GAAG,UAAU,CAAC,sBAAsB,CAAC,CAAC;AAC1D,MAAM,WAAW,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAC;AAEpD,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAE7C,MAAM,UAAU,GAAyC;IACvD,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,cAA2B,CAAC;IAClD,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,WAAwB,CAAC;CAC7C,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,MAAkC,EAAoB,EAAE,CAAC,CAAC;IAC/F,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;IAC1B,MAAM;CACP,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,UAAsB,EAAE,QAAiB,EAAoB,EAAE;IAC5F,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAExC,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvB,OAAO,sBAAsB,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,sBAAsB,CAAE,QAAQ,CAAC,MAAiC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC;AACjG,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,KAAkB,EAAmB,EAAE,CAAC,CAAC;IAC/D,IAAI,EAAE,KAAK,CAAC,YAAY,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY;IAC1D,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;CAC/B,CAAC,CAAC"}
|
|
@@ -1,82 +1,66 @@
|
|
|
1
1
|
# State Writeback Strategy
|
|
2
2
|
|
|
3
|
-
This document describes Outfitter's
|
|
3
|
+
This document describes Outfitter's model for handling writes that agent CLIs make inside a temporary projection — the generated configuration directory an adapter builds from a baked composition.
|
|
4
4
|
|
|
5
|
-
A
|
|
6
|
-
Outfitter makes those paths explicit: adapter-declared writable paths are materialized with a resolved `state_persistence` strategy before the child CLI starts, and non-persistent or unknown writes are diagnosed after the child exits.
|
|
5
|
+
A projection is temporary, but agent CLIs sometimes perform intentionally durable writes, such as logging in, installing plugins, changing settings, or updating MCP configuration. Outfitter makes those paths explicit: adapter-declared writable paths are materialized with a resolved `state_persistence` strategy before the child CLI starts, and non-persistent or unknown writes are diagnosed after the child exits.
|
|
7
6
|
|
|
8
7
|
## Functional model
|
|
9
8
|
|
|
10
|
-
Outfitter separates three kinds of files that may exist in a
|
|
9
|
+
Outfitter separates three kinds of files that may exist in a projection:
|
|
11
10
|
|
|
12
|
-
1. **Generated runtime files**: files Outfitter assembles from
|
|
13
|
-
Outfitter may regenerate these while the child agent is running when their source inputs change.
|
|
11
|
+
1. **Generated runtime files**: files Outfitter assembles from the baked composition and adapter rules.
|
|
14
12
|
2. **Declared state paths**: adapter-known files or directories the agent CLI may update intentionally, such as auth, settings, MCP config, plugins, caches, and sessions.
|
|
15
13
|
3. **Unknown writes**: files or directories the agent creates outside the adapter-declared state paths.
|
|
16
14
|
|
|
17
|
-
Only declared state paths can be made durable automatically.
|
|
18
|
-
Unknown writes are never silently persisted because Outfitter does not know their intended owner, merge rules, or durable destination.
|
|
19
|
-
Generated runtime files and declared state paths are deliberately handled separately so live profile/template updates do not erase or re-baseline agent state changes made during the same run.
|
|
15
|
+
Only declared state paths can be made durable automatically. Unknown writes are never silently persisted because Outfitter does not know their intended owner, merge rules, or durable destination. Generated runtime files and declared state paths are deliberately handled separately so composition regeneration does not erase or re-baseline agent state changes made during the same run.
|
|
20
16
|
|
|
21
17
|
The user-facing state update lifecycle is:
|
|
22
18
|
|
|
23
|
-
1. **
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
4. **Run the agent**.
|
|
30
|
-
The agent CLI reads and writes the composite profile as if it were its normal configuration directory.
|
|
31
|
-
5. **Classify changes after exit**.
|
|
32
|
-
Outfitter checks non-durable declared paths and unknown paths and reports or fails according to their strategies.
|
|
33
|
-
6. **Clean up temporary state**.
|
|
34
|
-
Temporary composite profile contents are discarded; durable symlink targets remain in their profile or native CLI location.
|
|
19
|
+
1. **Resolve settings.** Settings resolution determines the effective `state_persistence` map using normal settings precedence (`settings.local.yml` over `settings.yml`, project over user).
|
|
20
|
+
2. **Resolve adapter defaults.** For each path the selected adapter declares, Outfitter uses the settings override when present and otherwise uses the adapter default.
|
|
21
|
+
3. **Prepare the projection.** Durable paths are connected to a native CLI location; non-durable paths are created as normal temporary projection paths.
|
|
22
|
+
4. **Run the agent.** The agent CLI reads and writes the projection as if it were its normal configuration directory.
|
|
23
|
+
5. **Classify changes after exit.** Outfitter checks non-durable declared paths and unknown paths and reports, prompts, or fails according to their strategies.
|
|
24
|
+
6. **Clean up temporary state.** Temporary projection contents are discarded; durable symlink targets remain in their native CLI location.
|
|
35
25
|
|
|
36
26
|
## Current behavior
|
|
37
27
|
|
|
38
|
-
-
|
|
28
|
+
- Projections remain temporary and reproducible by default.
|
|
39
29
|
- Outfitter does not do generic post-run copy-back or JSON/YAML merge-back.
|
|
40
|
-
- Persistent state is represented by symlinking a
|
|
41
|
-
- Adapters may generate a concrete runtime file for a declared state path when they need deterministic launch-time reconciliation.
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
- Invalid or disallowed profile-requested `state_persistence` strategies fail before launch; adapter-internal reconciliation may still choose a one-run handling strategy for a generated runtime file.
|
|
30
|
+
- Persistent state is represented by symlinking a projection path to the native CLI fallback path.
|
|
31
|
+
- Adapters may generate a concrete runtime file for a declared state path when they need deterministic launch-time reconciliation. For example, the Pi adapter can generate a transformed `settings.json` that removes native `packages` entries already supplied by composition-controlled extensions, and then mark that declared path as `discard` for write detection during the run.
|
|
32
|
+
- Every adapter-declared state path has a resolved strategy before launch: settings overrides win, otherwise the adapter `default_strategy` is used, except for adapter-generated reconciliation files that are intentionally treated as discarded runtime files.
|
|
33
|
+
- Invalid or disallowed requested `state_persistence` strategies fail before launch; adapter-internal reconciliation may still choose a one-run handling strategy for a generated runtime file.
|
|
45
34
|
- Non-persistent `warn` and `error` strategies are checked after the child CLI exits.
|
|
46
35
|
- Unknown writes outside adapter-declared paths are checked with the adapter's `unknown` pseudo-path strategy.
|
|
47
|
-
-
|
|
48
|
-
When accepted by a declaration today, it is treated as a non-persistent diagnostic like `warn`.
|
|
36
|
+
- Baked artifacts and dumps never include declared state paths or their contents; state is runtime, not configuration.
|
|
49
37
|
|
|
50
38
|
## Non-goals
|
|
51
39
|
|
|
52
|
-
- Outfitter does not implement generic copy-back from the
|
|
40
|
+
- Outfitter does not implement generic copy-back from the projection to `.agents` trees.
|
|
53
41
|
- Outfitter does not implement generic structured merge-back.
|
|
54
42
|
- Outfitter does not silently persist unknown writes.
|
|
55
43
|
|
|
56
|
-
##
|
|
44
|
+
## Settings resolution and native fallback
|
|
57
45
|
|
|
58
|
-
State persistence is a normal
|
|
59
|
-
Its strategy overrides resolve through the same selected-profile stack as other profile data. When the user provides `--profile X`, only definitions of `X` and its explicit inheritance chain participate; the configured `default_profile` is selected only when no explicit profile is provided.
|
|
46
|
+
State persistence is a normal Outfitter setting. Its strategy overrides resolve through the same settings precedence as other settings data:
|
|
60
47
|
|
|
61
48
|
```text
|
|
62
|
-
project
|
|
63
|
-
project
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
49
|
+
<project>/.agents/settings.local.yml
|
|
50
|
+
<project>/.agents/settings.yml
|
|
51
|
+
~/.agents/settings.local.yml
|
|
52
|
+
~/.agents/settings.yml
|
|
53
|
+
cached remote settings
|
|
67
54
|
Outfitter defaults
|
|
68
55
|
```
|
|
69
56
|
|
|
70
|
-
Native CLI state is not
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
Claude Code `projects/` is additionally controlled by `controls.session_directory` or `controls.claude.session_directory` when set.
|
|
57
|
+
Native CLI state is not a configuration layer. For `symlink` paths, the selected adapter resolves a native fallback location directly, such as `~/.pi/agent/...` for most Pi state paths, `~/.claude/...` for most Claude Code state paths, or `<cache_directory>/utilities` for Pi `utilities/` and `bin/`. The native fallback does not participate in resource resolution or merge precedence and cannot contribute resources. Claude Code `projects/` is additionally controlled by the session-directory setting when set.
|
|
58
|
+
|
|
59
|
+
For a [ported Claude Code setup](../documentation/porting-claude.md), configuration entries under `~/.claude` are symlinks into `~/.agents/`, so a durable write through the projection's `skills/` link lands in the protocol tree. The porting arrangement is created by setup; the state machinery just follows the links.
|
|
74
60
|
|
|
75
61
|
## Path-keyed adapter declarations
|
|
76
62
|
|
|
77
|
-
Adapters declare writable state paths directly, using relative file paths as keys.
|
|
78
|
-
Directory paths use a trailing slash.
|
|
79
|
-
The same key is used for adapter coverage, `state_persistence` overrides, profile resource lookup, native fallback lookup, and composite profile materialization.
|
|
63
|
+
Adapters declare writable state paths directly, using relative file paths as keys. Directory paths use a trailing slash. The same key is used for adapter coverage, `state_persistence` overrides, native fallback lookup, and projection materialization.
|
|
80
64
|
|
|
81
65
|
The Pi adapter currently declares:
|
|
82
66
|
|
|
@@ -90,11 +74,12 @@ state_paths:
|
|
|
90
74
|
default_strategy: symlink
|
|
91
75
|
allowed_strategies: [symlink, warn, error, prompt]
|
|
92
76
|
note: >-
|
|
93
|
-
When
|
|
94
|
-
Outfitter may generate a transformed runtime settings.json and
|
|
95
|
-
declared path as discard for that launch. That discard
|
|
96
|
-
adapter-internal; users still cannot request
|
|
97
|
-
because discard is not listed in
|
|
77
|
+
When composition-controlled Pi extensions duplicate native settings
|
|
78
|
+
packages, Outfitter may generate a transformed runtime settings.json and
|
|
79
|
+
treat this declared path as discard for that launch. That discard
|
|
80
|
+
handling is adapter-internal; users still cannot request
|
|
81
|
+
settings.json: discard because discard is not listed in
|
|
82
|
+
allowed_strategies.
|
|
98
83
|
|
|
99
84
|
keybindings.json:
|
|
100
85
|
default_strategy: symlink
|
|
@@ -190,43 +175,9 @@ state_paths:
|
|
|
190
175
|
allowed_strategies: [discard, warn, error, prompt]
|
|
191
176
|
```
|
|
192
177
|
|
|
193
|
-
## Profile layout for state files
|
|
194
|
-
|
|
195
|
-
State files live under the relevant CLI-specific profile folder:
|
|
196
|
-
|
|
197
|
-
```text
|
|
198
|
-
profiles/
|
|
199
|
-
default/
|
|
200
|
-
profile.yml
|
|
201
|
-
cli_specific/
|
|
202
|
-
pi/
|
|
203
|
-
auth.json
|
|
204
|
-
settings.json
|
|
205
|
-
keybindings.json
|
|
206
|
-
plugins/
|
|
207
|
-
claude/
|
|
208
|
-
settings.json
|
|
209
|
-
skills/
|
|
210
|
-
commands/
|
|
211
|
-
plugins/
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Except for special adapter paths described below, when a selected strategy is `symlink`, Outfitter searches the resolved profile folders from highest to lowest precedence for `cli_specific/<adapter>/<state-path>`.
|
|
215
|
-
If a profile contains the file or directory, Outfitter symlinks the composite profile path to that source.
|
|
216
|
-
|
|
217
|
-
For most Pi paths, if no profile source exists, Outfitter falls back to the corresponding native Pi agent path under `~/.pi/agent`.
|
|
218
|
-
Missing native fallback files/directories are created so the composite profile symlink has a durable destination.
|
|
219
|
-
|
|
220
|
-
Pi `utilities/` and `bin/` are special cache-backed paths: both resolve to `<cache_directory>/utilities` instead of profile or native Pi state.
|
|
221
|
-
This keeps pi-managed helper binaries reusable across temporary composite profiles without treating them as user-editable profile files.
|
|
222
|
-
|
|
223
|
-
For most Claude Code paths, if no profile source exists, Outfitter falls back to the corresponding native Claude Code path under `~/.claude`.
|
|
224
|
-
Claude Code `projects/` is special: `controls.claude.session_directory` overrides generic `controls.session_directory`, and the selected session directory becomes the `projects/` symlink source.
|
|
225
|
-
If neither session-directory control is present, `projects/` falls back to `~/.claude/projects`.
|
|
226
|
-
|
|
227
178
|
## `state_persistence`
|
|
228
179
|
|
|
229
|
-
|
|
180
|
+
Settings may override persistence by mapping adapter-declared paths to strategy names:
|
|
230
181
|
|
|
231
182
|
```yaml
|
|
232
183
|
state_persistence:
|
|
@@ -238,11 +189,9 @@ state_persistence:
|
|
|
238
189
|
unknown: warn
|
|
239
190
|
```
|
|
240
191
|
|
|
241
|
-
The values are concrete strategy names.
|
|
242
|
-
`state_persistence` only needs overrides; omitted paths use the adapter declaration's `default_strategy`.
|
|
192
|
+
The values are concrete strategy names. `state_persistence` only needs overrides; omitted paths use the adapter declaration's `default_strategy`.
|
|
243
193
|
|
|
244
|
-
`state_persistence` is validated by the
|
|
245
|
-
Outfitter also validates the resolved strategy against the adapter declaration before launch.
|
|
194
|
+
`state_persistence` is validated by the settings JSON Schema at read boundaries. Outfitter also validates the resolved strategy against the adapter declaration before launch.
|
|
246
195
|
|
|
247
196
|
Functional examples:
|
|
248
197
|
|
|
@@ -256,7 +205,7 @@ state_persistence:
|
|
|
256
205
|
```
|
|
257
206
|
|
|
258
207
|
```yaml
|
|
259
|
-
# CI
|
|
208
|
+
# CI settings: fail if pi changes settings, MCP config, or unknown files.
|
|
260
209
|
state_persistence:
|
|
261
210
|
settings.json: error
|
|
262
211
|
mcp.json: error
|
|
@@ -265,25 +214,25 @@ state_persistence:
|
|
|
265
214
|
```
|
|
266
215
|
|
|
267
216
|
```yaml
|
|
268
|
-
# Exploratory
|
|
217
|
+
# Exploratory settings: allow plugin experiments but report them after exit.
|
|
269
218
|
state_persistence:
|
|
270
219
|
plugins/: warn
|
|
271
220
|
unknown: warn
|
|
272
221
|
```
|
|
273
222
|
|
|
274
|
-
##
|
|
223
|
+
## Projection materialization
|
|
275
224
|
|
|
276
225
|
Before launch, Outfitter processes each adapter-declared state path:
|
|
277
226
|
|
|
278
|
-
1. Resolve the path's strategy from
|
|
227
|
+
1. Resolve the path's strategy from `state_persistence` overrides, then the adapter `default_strategy`.
|
|
279
228
|
2. Validate that the strategy is allowed for that path.
|
|
280
|
-
3. Resolve
|
|
281
|
-
4. Materialize the
|
|
229
|
+
3. Resolve the native fallback source when the strategy is `symlink`; missing native fallback files/directories are created so the symlink has a durable destination.
|
|
230
|
+
4. Materialize the projection path.
|
|
282
231
|
5. Record a baseline fingerprint for non-persistent and unknown write detection.
|
|
283
232
|
|
|
284
|
-
For `symlink`, Outfitter creates a symlink from the
|
|
233
|
+
For `symlink`, Outfitter creates a symlink from the projection path to the resolved native CLI source. For `discard`, `warn`, `error`, and `prompt`, Outfitter creates normal temporary projection paths where needed and observes whether they changed.
|
|
285
234
|
|
|
286
|
-
|
|
235
|
+
Pi `utilities/` and `bin/` are special cache-backed paths: both resolve to `<cache_directory>/utilities` instead of native Pi state, keeping pi-managed helper binaries reusable across temporary projections. Claude Code `projects/` uses the configured session directory when set, otherwise `~/.claude/projects`.
|
|
287
236
|
|
|
288
237
|
## Unknown writes
|
|
289
238
|
|
|
@@ -294,57 +243,40 @@ state_persistence:
|
|
|
294
243
|
unknown: warn
|
|
295
244
|
```
|
|
296
245
|
|
|
297
|
-
Supported `unknown` strategies are non-persistent only:
|
|
298
|
-
|
|
299
|
-
- `discard`
|
|
300
|
-
- `warn`
|
|
301
|
-
- `error`
|
|
302
|
-
- `prompt`
|
|
303
|
-
|
|
304
|
-
`unknown` does not support `symlink`, because there is no declared durable destination.
|
|
246
|
+
Supported `unknown` strategies are non-persistent only: `discard`, `warn`, `error`, and `prompt`. `unknown` does not support `symlink`, because there is no declared durable destination; `unknown: prompt` reports as a warning with an explanation.
|
|
305
247
|
|
|
306
248
|
## Strategy selection guide
|
|
307
249
|
|
|
308
|
-
Use `symlink` when a write is part of durable agent setup, such as logging in, editing native settings, updating MCP config, or installing plugins that should be reused.
|
|
309
|
-
Use `discard` when the data is useful only during the current run, such as cache entries or throwaway sessions.
|
|
310
|
-
Use `warn` when mutation is acceptable but should be visible to the user.
|
|
311
|
-
Use `error` when mutation means the run was not reproducible enough, especially in CI or locked-down project profiles.
|
|
312
|
-
Use `prompt` only as a forward-compatible declaration for future interactive handling.
|
|
250
|
+
Use `symlink` when a write is part of durable agent setup, such as logging in, editing native settings, updating MCP config, or installing plugins that should be reused. Use `discard` when the data is useful only during the current run, such as cache entries or throwaway sessions. Use `warn` when mutation is acceptable but should be visible to the user. Use `error` when mutation means the run was not reproducible enough, especially in CI or locked-down projects. Use `prompt` when the user should decide interactively after each run.
|
|
313
251
|
|
|
314
252
|
## Strategies
|
|
315
253
|
|
|
316
254
|
### `symlink`
|
|
317
255
|
|
|
318
|
-
Outfitter resolves the state path
|
|
319
|
-
Persistence happens because the CLI writes through the symlink to an intentional file or directory.
|
|
256
|
+
Outfitter resolves the state path to its native CLI fallback and symlinks that source into the projection. Persistence happens because the CLI writes through the symlink to an intentional file or directory.
|
|
320
257
|
|
|
321
258
|
### `discard`
|
|
322
259
|
|
|
323
|
-
Writes are allowed in the
|
|
324
|
-
Outfitter does not emit diagnostics for changed `discard` paths.
|
|
260
|
+
Writes are allowed in the projection and are thrown away when the projection is deleted. Outfitter does not emit diagnostics for changed `discard` paths.
|
|
325
261
|
|
|
326
262
|
### `warn`
|
|
327
263
|
|
|
328
|
-
Writes are allowed, discarded, and reported after the child exits.
|
|
329
|
-
`--strict` makes these warnings fatal.
|
|
264
|
+
Writes are allowed, discarded, and reported after the child exits. `--strict` makes these warnings fatal.
|
|
330
265
|
|
|
331
266
|
### `error`
|
|
332
267
|
|
|
333
|
-
Writes are allowed during the child process but cause Outfitter to fail after the child exits if the path changed.
|
|
334
|
-
This is useful for CI and strict reproducibility.
|
|
268
|
+
Writes are allowed during the child process but cause Outfitter to fail after the child exits if the path changed. This is useful for CI and strict reproducibility.
|
|
335
269
|
|
|
336
270
|
### `prompt`
|
|
337
271
|
|
|
338
|
-
`prompt` is
|
|
339
|
-
Current implementations that allow it treat writes as non-persistent diagnostics, equivalent to `warn`, with the strategy name preserved in the message.
|
|
272
|
+
When a `prompt` path changed and both stdin and stdout are interactive terminals, Outfitter asks after the child exits: **persist** (copy the change to the durable destination once), **discard**, or **always** (persist and record a `symlink` override in the editable settings scope). Outfitter never mutates a synced catalog cache; when the active configuration is remote, the change is persisted once with a warning that the choice could not be recorded. In non-interactive sessions, `prompt` falls back to `warn` with an explicit `prompt skipped: non-interactive` notice.
|
|
340
273
|
|
|
341
274
|
## Rationale
|
|
342
275
|
|
|
343
276
|
Path-keyed state declarations keep the model simple:
|
|
344
277
|
|
|
345
278
|
- the adapter declares the paths it knows the CLI may write and their default strategies;
|
|
346
|
-
- profiles may provide files at those same paths;
|
|
347
279
|
- the native fallback exposes native CLI files at those same paths;
|
|
348
280
|
- `state_persistence` says what to do with each path.
|
|
349
281
|
|
|
350
|
-
This avoids ambiguous writeback behavior and gives users a clear rule: if a CLI write should persist, configure that
|
|
282
|
+
This avoids ambiguous writeback behavior and gives users a clear rule: if a CLI write should persist, configure that projection path as `symlink` and accept the native file that should receive the mutation. Configuration flows the other direction — from the `.agents` tree into the projection — and never back.
|
|
@@ -1,24 +1,45 @@
|
|
|
1
1
|
# Outfitter documentation
|
|
2
2
|
|
|
3
|
-
User-facing Outfitter documentation.
|
|
3
|
+
User-facing Outfitter documentation. These docs describe the [RFC #165](https://github.com/ai-outfitter/outfitter/issues/165) dotagents end state.
|
|
4
|
+
|
|
5
|
+
## Getting started
|
|
4
6
|
|
|
5
7
|
- [Getting started](./getting-started.md)
|
|
6
8
|
- [Concepts](./concepts.md)
|
|
7
9
|
- [CLI reference](./cli.md)
|
|
8
10
|
- [First-time CLI agent users](./first-time-cli-agent-users.md)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
14
|
-
- [
|
|
15
|
-
- [
|
|
16
|
-
- [
|
|
11
|
+
|
|
12
|
+
## Core concepts
|
|
13
|
+
|
|
14
|
+
- [Settings](./settings.md) — Scopes, schema, and the flat `settings.local.yml` override file.
|
|
15
|
+
- [Agents](./agents.md) — The `agents/<id>/agent.md` resource and its loadout — what you run.
|
|
16
|
+
- [Agent profiles](./profiles.md) — Why an agent and its loadout _is_ the profile.
|
|
17
|
+
- [Personas](./personas.md) — The base-agent-plus-persona-documents review convention.
|
|
18
|
+
- [Subagents](./subagents.md) — Agents projected as harness delegates; leader-agent delegation.
|
|
19
|
+
- [Skills](./skills.md) — Capability packages with progressive disclosure, references, and routing.
|
|
20
|
+
- [Tasks](./tasks.md) — Placeholder for a separate upcoming RFC.
|
|
21
|
+
|
|
22
|
+
## Operations
|
|
23
|
+
|
|
24
|
+
- [Catalogs](./catalogs.md) — Publish and consume shareable `.agents` payloads; standalone and colocated layouts.
|
|
25
|
+
- [Dump](./dump-and-bake.md) — Deterministic, self-contained `.agents/` dumps.
|
|
26
|
+
- [Running an agent in GitHub Actions](./actions.md)
|
|
27
|
+
- [Hooks](./hooks.md) — Harness hook wiring and the protocol gap.
|
|
17
28
|
- [State persistence](./state.md)
|
|
29
|
+
- [Adapter support matrix](./support-matrix.md)
|
|
30
|
+
|
|
31
|
+
## Adopting Outfitter
|
|
32
|
+
|
|
33
|
+
- [Switching to Outfitter](./switching-to-outfitter.md)
|
|
34
|
+
- [Porting a Claude Code setup](./porting-claude.md) — Port `~/.claude` into `~/.agents/` with a symlink back.
|
|
35
|
+
- [Local dotagents development](./local-development.md) — A personal standalone `.agents` repo that trickles upstream.
|
|
36
|
+
- [Migration from legacy profiles](./migration.md)
|
|
37
|
+
- [Iterating on an agent](./iterating-on-profiles.md)
|
|
38
|
+
- [Best practices](./best-practices.md)
|
|
18
39
|
- [Philosophy](../philosophy.md)
|
|
19
40
|
|
|
20
41
|
## Use cases
|
|
21
42
|
|
|
22
|
-
- [Organization
|
|
23
|
-
- [Engineering
|
|
24
|
-
- [Persona reviews](./usecases/persona-reviews.md) —
|
|
43
|
+
- [Organization catalog](./usecases/organization-profile-catalog.md) — Publish shared org resources and defaults through an `owner/.outfitter` control repository.
|
|
44
|
+
- [Engineering catalog](./usecases/engineering.md) — Package engineering agents and skills for repeatable workflows.
|
|
45
|
+
- [Persona reviews](./usecases/persona-reviews.md) — A base review agent plus customer-persona documents for feedback on ideas, docs, and designs.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Running
|
|
1
|
+
# Running an agent in GitHub Actions
|
|
2
2
|
|
|
3
|
-
[`ai-outfitter/actions`](https://github.com/ai-outfitter/actions) runs an Outfitter
|
|
3
|
+
[`ai-outfitter/actions`](https://github.com/ai-outfitter/actions) runs an Outfitter [agent](./agents.md) non-interactively inside a GitHub Actions workflow. The Action asks Outfitter to resolve and compose the selected agent — the same loadout it would compose locally — then launches the harness in headless print mode, so the agent does one unit of work per workflow run and exits. Wire it to any trigger and an agent becomes a CI worker: a PR reviewer, a scheduled commit auditor, an issue triager.
|
|
4
4
|
|
|
5
5
|
```yaml
|
|
6
6
|
# .github/workflows/issue-triage.yml
|
|
@@ -20,78 +20,61 @@ jobs:
|
|
|
20
20
|
runs-on: ubuntu-latest
|
|
21
21
|
steps:
|
|
22
22
|
- uses: actions/checkout@v4
|
|
23
|
-
- uses: ai-outfitter/actions@
|
|
23
|
+
- uses: ai-outfitter/actions@v2
|
|
24
24
|
with:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
${{ github.repository }}
|
|
25
|
+
agent: issue-triage
|
|
26
|
+
source: ${{ github.workspace }}/.agents # or owner/.agent + a pinned ref
|
|
27
|
+
inputs: |
|
|
28
|
+
issue_number: ${{ github.event.issue.number }}
|
|
29
|
+
repository: ${{ github.repository }}
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
The
|
|
32
|
+
The Action consumes an agent ID, a local or pinned remote source, structured inputs, and runtime-only options (harness, credentials, working directory). It does not reproduce composition logic itself — it goes through Outfitter's resolver so a CI run and a local run compose identically given the same sources and refs.
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
> **Note:** a dedicated **task**-bake path — freezing a named work contract and its typed inputs into an immutable artifact before launch — is the subject of a [separate upcoming RFC](./tasks.md). Until then the Action runs an agent with structured inputs; the `inputs:` shape above is forward-compatible with that work.
|
|
35
35
|
|
|
36
|
-
##
|
|
36
|
+
## Division of ownership
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
`ai-outfitter/actions` workflow. It is not an Outfitter object and Outfitter does
|
|
40
|
-
not create or parse it. GitHub Actions interpolates the selected `github`
|
|
41
|
-
expression values before invoking Outfitter, giving the profile metadata that
|
|
42
|
-
the workflow — not the event author — chose to pass. That does not make every
|
|
43
|
-
value trustworthy: branch and tag names, labels, titles, and logins are
|
|
44
|
-
user-influenced, so route on them as opaque identifiers and never treat them
|
|
45
|
-
as instructions.
|
|
38
|
+
The workflow YAML owns the GitHub side; the agent owns the work:
|
|
46
39
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
repository: ${{ github.repository }}
|
|
56
|
-
event_name: ${{ github.event_name }}
|
|
57
|
-
issue_number: ${{ github.event.issue.number || '' }}
|
|
58
|
-
```
|
|
40
|
+
| Workflow YAML owns | Agent owns |
|
|
41
|
+
| ------------------------------------------ | ----------------------------------- |
|
|
42
|
+
| Triggers (`on:`) | The objective and prompt |
|
|
43
|
+
| Checkout | Identity and posture |
|
|
44
|
+
| `permissions:` and credentials | Its loadout: skills, subagents, mcp |
|
|
45
|
+
| Execution identity | How it uses its inputs |
|
|
46
|
+
| Trusted event identifiers passed as inputs | Completion behavior |
|
|
47
|
+
| GitHub-specific result handling | |
|
|
59
48
|
|
|
60
|
-
|
|
61
|
-
workflow's declared events (for example `sha`, `issue_labels`, or a
|
|
62
|
-
deployment's `environment_url` when those events are in play). Add a
|
|
63
|
-
workflow-owned discriminator, such as `report_kind: weekly-kpi`, when GitHub's
|
|
64
|
-
event metadata cannot distinguish scheduled behaviors.
|
|
49
|
+
Pass only the identifiers the agent expects (numbers, SHAs, repository names, workflow-owned discriminators). Never interpolate issue bodies, PR bodies, comments, diffs, or fetched page content into inputs — user-influenced values like titles and branch names are opaque identifiers, not instructions. A selected skill retrieves untrusted source material itself with trusted tools.
|
|
65
50
|
|
|
66
|
-
|
|
67
|
-
procedures in the skills themselves. See
|
|
68
|
-
[Keep routing concise](./best-practices.md#keep-routing-concise) for that design
|
|
69
|
-
boundary.
|
|
51
|
+
## Setup: the `outfitter-actions` skill
|
|
70
52
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
untrusted source material it needs with trusted tools.
|
|
53
|
+
The workflow surface is installed and maintained by the `outfitter-actions` setup skill shipped in the `ai-outfitter/actions` catalog, which includes the reusable workflow template (`template/github-action.yml`). Run it in an agent session to create or update your project's workflows.
|
|
54
|
+
|
|
55
|
+
The setup skill consolidates compatible agents into as few workflows as practical: separate workflows are justified only by different triggers, permissions, credentials, isolation, or other GitHub-enforced boundaries. Domain skills such as `reports` or `issue-triage` do not ship their own workflow templates.
|
|
75
56
|
|
|
76
57
|
## Zero-key inference with GitHub Models
|
|
77
58
|
|
|
78
|
-
CI agents don't need a paid provider key. [GitHub Models](https://docs.github.com/en/github-models) serves hosted models authenticated by the workflow's own `GITHUB_TOKEN`: grant `models: read` in the `permissions:` block
|
|
59
|
+
CI agents don't need a paid provider key. [GitHub Models](https://docs.github.com/en/github-models) serves hosted models authenticated by the workflow's own `GITHUB_TOKEN`: grant `models: read` in the `permissions:` block and point the tree's `models.json` at `https://models.github.ai/inference` with `"apiKey": "$GITHUB_TOKEN"`. The Action's README documents the full recipe, including model-selection gotchas (catalog availability, tool-call wire compatibility, and models too weak to hold an agentic loop).
|
|
79
60
|
|
|
80
61
|
Mind the rate limits: the included tier is sized for event-driven, one-shot jobs. Concurrent runs of a large model can 429; high-volume review loops need a provider key.
|
|
81
62
|
|
|
82
|
-
## Write
|
|
63
|
+
## Write agents for headless runs
|
|
83
64
|
|
|
84
|
-
A
|
|
65
|
+
A composition that behaves well interactively can still fail silently in CI. Lessons from running triage agents in production:
|
|
85
66
|
|
|
86
|
-
- **Stdout is invisible.** In print mode nobody reads what the agent says — only its side effects matter.
|
|
67
|
+
- **Stdout is invisible.** In print mode nobody reads what the agent says — only its side effects matter. Make the agent's completion criteria name the exact `gh` side effects (comment, label, push); otherwise models will print the deliverable as their answer and exit green.
|
|
87
68
|
- **Quote-safe posting.** When the agent posts text derived from untrusted input (issue bodies, diffs) back through `gh`, require a quoted heredoc plus `--body-file`, never inline `--body "..."` — backticks in a double-quoted body are executed by the shell.
|
|
88
|
-
- **Verify side effects, not exit codes.** A green run is not proof of work. Add a post-agent step that asserts the expected side effects landed — the
|
|
89
|
-
- **Hard limits in the
|
|
69
|
+
- **Verify side effects, not exit codes.** A green run is not proof of work. Add a post-agent step that asserts the expected side effects landed — the Action ships [`scripts/validate-triage.sh`](https://github.com/ai-outfitter/actions/blob/main/scripts/validate-triage.sh) as a reference for triage-style jobs.
|
|
70
|
+
- **Hard limits in the contract.** Enumerate exactly what the agent may do (which labels, how many comments, no closing/editing) in the agent's own definition, and treat fetched content as data to classify, never instructions.
|
|
90
71
|
|
|
91
72
|
## Scope the token
|
|
92
73
|
|
|
93
|
-
The agent runs arbitrary `gh`/`git`/shell with whatever token you hand it, against untrusted input. Prefer the workflow's own `GITHUB_TOKEN` with an explicit least-privilege `permissions:` block; use a fine-grained PAT from a dedicated machine account only when the agent needs its own identity. Never use a human's PAT. The
|
|
74
|
+
The agent runs arbitrary `gh`/`git`/shell with whatever token you hand it, against untrusted input. Prefer the workflow's own `GITHUB_TOKEN` with an explicit least-privilege `permissions:` block; use a fine-grained PAT from a dedicated machine account only when the agent needs its own identity. Never use a human's PAT. The Action's [token-permissions](https://github.com/ai-outfitter/actions/blob/main/docs/token-permissions.md) and [bot-account](https://github.com/ai-outfitter/actions/blob/main/docs/bot-account.md) guides cover this in depth, including prompt-injection trust boundaries.
|
|
75
|
+
|
|
76
|
+
Pin remote sources consumed in CI to full commit SHAs — see [Trust and review](./catalogs.md#trust-and-review).
|
|
94
77
|
|
|
95
78
|
## More examples
|
|
96
79
|
|
|
97
|
-
The
|
|
80
|
+
The Action's [`examples/`](https://github.com/ai-outfitter/actions/tree/main/examples) directory covers scheduled commit review, PR ready-for-review reviews, sensitive-path audits, assigned-task agents, and zero-key issue triage on GitHub Models. A complete live setup runs in [`ai-outfitter/.outfitter`](https://github.com/ai-outfitter/.outfitter) as the organization's own `weekly-kpis` agent.
|